Automated rollback of commit 8c2416311f7b2c5410e620197baacf9d82b86ebd.

PiperOrigin-RevId: 580960903
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 27a5772..8630cdc 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -135,7 +135,6 @@
 class MapValueRef;
 class MapIterator;
 class MapReflectionTester;
-class TextFormat;
 
 namespace internal {
 struct FuzzPeer;
@@ -1011,7 +1010,6 @@
     return schema_.IsSplit(field);
   }
 
-  friend class google::protobuf::TextFormat;
   friend class FastReflectionBase;
   friend class FastReflectionMessageMutator;
   friend bool internal::IsDescendant(Message& root, const Message& message);
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index e29b07b..9abd847 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -295,14 +295,6 @@
 }
 }  // namespace
 
-const void* TextFormat::Parser::UnsetFieldsMetadata::GetUnsetFieldAddress(
-    const Message& message, const Reflection& reflection,
-    const FieldDescriptor& fd) {
-  // reflection->GetRaw() is a simple cast for any non-repeated type, so for
-  // simplicity we just pass in char as the template argument.
-  return &reflection.GetRaw<char>(message, &fd);
-}
-
 // ===========================================================================
 // Internal class for parsing an ASCII representation of a Protocol Message.
 // This class makes use of the Protocol Message compiler's tokenizer found
@@ -339,7 +331,7 @@
              bool allow_unknown_extension, bool allow_unknown_enum,
              bool allow_field_number, bool allow_relaxed_whitespace,
              bool allow_partial, int recursion_limit,
-             UnsetFieldsMetadata* no_op_fields)
+             bool error_on_no_op_fields)
       : error_collector_(error_collector),
         finder_(finder),
         parse_info_tree_(parse_info_tree),
@@ -357,7 +349,7 @@
         recursion_limit_(recursion_limit),
         had_silent_marker_(false),
         had_errors_(false),
-        no_op_fields_(no_op_fields) {
+        error_on_no_op_fields_(error_on_no_op_fields) {
     // For backwards-compatibility with proto1, we need to allow the 'f' suffix
     // for floats.
     tokenizer_.set_allow_f_after_float(true);
@@ -842,21 +834,19 @@
 // When checking for no-op operations, We verify that both the existing value in
 // the message and the new value are the default. If the existing field value is
 // not the default, setting it to the default should not be treated as a no-op.
-// The pointer of this is kept in no_op_fields_ for bookkeeping.
-#define SET_FIELD(CPPTYPE, CPPTYPELCASE, VALUE)                            \
-  if (field->is_repeated()) {                                              \
-    reflection->Add##CPPTYPE(message, field, VALUE);                       \
-  } else {                                                                 \
-    if (no_op_fields_ && !field->has_presence() &&                         \
-        field->default_value_##CPPTYPELCASE() ==                           \
-            reflection->Get##CPPTYPE(*message, field) &&                   \
-        field->default_value_##CPPTYPELCASE() == VALUE) {                  \
-      no_op_fields_->addresses_.insert(                                    \
-          UnsetFieldsMetadata::GetUnsetFieldAddress(*message, *reflection, \
-                                                    *field));              \
-    } else {                                                               \
-      reflection->Set##CPPTYPE(message, field, std::move(VALUE));          \
-    }                                                                      \
+#define SET_FIELD(CPPTYPE, CPPTYPELCASE, VALUE)                   \
+  if (field->is_repeated()) {                                     \
+    reflection->Add##CPPTYPE(message, field, VALUE);              \
+  } else {                                                        \
+    if (error_on_no_op_fields_ && !field->has_presence() &&       \
+        field->default_value_##CPPTYPELCASE() ==                  \
+            reflection->Get##CPPTYPE(*message, field) &&          \
+        field->default_value_##CPPTYPELCASE() == VALUE) {         \
+      ReportError("Input field " + field->full_name() +           \
+                  " did not change resulting proto.");            \
+    } else {                                                      \
+      reflection->Set##CPPTYPE(message, field, std::move(VALUE)); \
+    }                                                             \
   }
 
     switch (field->cpp_type()) {
@@ -1439,7 +1429,7 @@
   int recursion_limit_;
   bool had_silent_marker_;
   bool had_errors_;
-  UnsetFieldsMetadata* no_op_fields_{};
+  bool error_on_no_op_fields_;
 
 };
 
@@ -1737,7 +1727,7 @@
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_extension_, allow_unknown_enum_,
                     allow_field_number_, allow_relaxed_whitespace_,
-                    allow_partial_, recursion_limit_, no_op_fields_);
+                    allow_partial_, recursion_limit_, error_on_no_op_fields_);
   return MergeUsingImpl(input, output, &parser);
 }
 
@@ -1762,7 +1752,7 @@
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_extension_, allow_unknown_enum_,
                     allow_field_number_, allow_relaxed_whitespace_,
-                    allow_partial_, recursion_limit_, no_op_fields_);
+                    allow_partial_, recursion_limit_, error_on_no_op_fields_);
   return MergeUsingImpl(input, output, &parser);
 }
 
@@ -1798,7 +1788,7 @@
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_extension_, allow_unknown_enum_,
                     allow_field_number_, allow_relaxed_whitespace_,
-                    allow_partial_, recursion_limit_, no_op_fields_);
+                    allow_partial_, recursion_limit_, error_on_no_op_fields_);
   return parser.ParseField(field, output);
 }
 
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index e16ed98..f851c91 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -21,7 +21,6 @@
 #include <vector>
 
 #include "absl/container/flat_hash_map.h"
-#include "absl/container/flat_hash_set.h"
 #include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/descriptor.h"
@@ -82,9 +81,6 @@
 // Converts a protobuf message to a string with redaction enabled.
 PROTOBUF_EXPORT std::string StringifyMessage(const Message& message,
                                              Option option);
-
-class UnsetFieldsMetadataTextFormatTestUtil;
-class UnsetFieldsMetadataMessageDifferencerTestUtil;
 }  // namespace internal
 
 // This class implements protocol buffer text format, colloquially known as text
@@ -723,40 +719,11 @@
     // the maximum allowed nesting of proto messages.
     void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
 
-    // Uniquely addresses fields in a message that was explicitly unset in
-    // textproto. Example:
-    // "some_int_field: 0"
-    // where some_int_field is non-optional.
-    //
-    // This class should only be used to pass data between the text_format
-    // parser and the MessageDifferencer.
-    class UnsetFieldsMetadata {
-     public:
-      UnsetFieldsMetadata() = default;
-
-     private:
-      // Return a pointer to the unset field in the given message.
-      static const void* GetUnsetFieldAddress(const Message& message,
-                                              const Reflection& reflection,
-                                              const FieldDescriptor& fd);
-
-      // List of addresses of explicitly unset proto fields.
-      absl::flat_hash_set<const void*> addresses_;
-
-      friend class ::google::protobuf::internal::
-          UnsetFieldsMetadataMessageDifferencerTestUtil;
-      friend class ::google::protobuf::internal::UnsetFieldsMetadataTextFormatTestUtil;
-      friend class ::google::protobuf::util::MessageDifferencer;
-      friend class ::google::protobuf::TextFormat::Parser;
-    };
-
-    // If called, the parser will report the parsed fields that had no
+    // If called, the parser will report an error if a parsed field had no
     // effect on the resulting proto (for example, fields with no presence that
-    // were set to their default value). These can be passed to the Partially()
-    // matcher as an indicator to explicitly check these fields are missing
-    // in the actual.
-    void OutputNoOpFields(UnsetFieldsMetadata* no_op_fields) {
-      no_op_fields_ = no_op_fields;
+    // were set to their default value).
+    void ErrorOnNoOpFields(bool return_error) {
+      error_on_no_op_fields_ = return_error;
     }
 
    private:
@@ -781,7 +748,7 @@
     bool allow_relaxed_whitespace_;
     bool allow_singular_overwrites_;
     int recursion_limit_;
-    UnsetFieldsMetadata* no_op_fields_ = nullptr;
+    bool error_on_no_op_fields_ = false;
   };
 
 
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 13fbf33..9f60c9f 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -15,11 +15,9 @@
 #include <stdlib.h>
 
 #include <atomic>
-#include <cstdint>
 #include <limits>
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "google/protobuf/testing/file.h"
 #include "google/protobuf/testing/file.h"
@@ -36,7 +34,6 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_replace.h"
 #include "absl/strings/substitute.h"
-#include "google/protobuf/descriptor.h"
 #include "google/protobuf/io/tokenizer.h"
 #include "google/protobuf/io/zero_copy_stream_impl.h"
 #include "google/protobuf/map_unittest.pb.h"
@@ -55,33 +52,10 @@
 namespace google {
 namespace protobuf {
 
-namespace internal {
-class UnsetFieldsMetadataTextFormatTestUtil {
- public:
-  static std::vector<const void*> GetRawAddresses(
-      const TextFormat::Parser::UnsetFieldsMetadata& metadata) {
-    return std::vector<const void*>(metadata.addresses_.begin(),
-                                    metadata.addresses_.end());
-  }
-  static const void* GetAddress(const Message& message,
-                                const Reflection& reflection,
-                                const FieldDescriptor& fd) {
-    return TextFormat::Parser::UnsetFieldsMetadata::GetUnsetFieldAddress(
-        message, reflection, fd);
-  }
-
-  static int32_t NumFields(
-      const TextFormat::Parser::UnsetFieldsMetadata& metadata) {
-    return metadata.addresses_.size();
-  }
-};
-}  // namespace internal
-
 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
 namespace text_format_unittest {
 
 using ::google::protobuf::internal::kDebugStringSilentMarker;
-using ::google::protobuf::internal::UnsetFieldsMetadataTextFormatTestUtil;
 using ::testing::AllOf;
 using ::testing::HasSubstr;
 
@@ -1023,207 +997,86 @@
   EXPECT_EQ(-2147483648, proto.repeated_nested_enum(3));
 }
 
-TEST_F(TextFormatTest, PopulatesNoOpFields) {
+TEST_F(TextFormatTest, ErrorOnNoOpFieldsProto3) {
   proto3_unittest::TestAllTypes proto;
   TextFormat::Parser parser;
-  TextFormat::Parser::UnsetFieldsMetadata no_op_fields;
-  parser.OutputNoOpFields(&no_op_fields);
+  parser.ErrorOnNoOpFields(true);
 
   {
-    no_op_fields = {};
     const absl::string_view singular_int_parse_string = "optional_int32: 0";
     EXPECT_TRUE(TextFormat::ParseFromString(singular_int_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(singular_int_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(singular_int_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view singular_bool_parse_string = "optional_bool: false";
     EXPECT_TRUE(
         TextFormat::ParseFromString(singular_bool_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(singular_bool_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(singular_bool_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view singular_string_parse_string =
         "optional_string: ''";
     EXPECT_TRUE(
         TextFormat::ParseFromString(singular_string_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(singular_string_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(singular_string_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view nested_message_parse_string =
         "optional_nested_message { bb: 0 } ";
     EXPECT_TRUE(
         TextFormat::ParseFromString(nested_message_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(nested_message_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(nested_message_parse_string, &proto));
   }
   {
-    no_op_fields = {};
-    const absl::string_view nested_message_parse_string =
-        "optional_nested_message { bb: 1 } ";
-    EXPECT_TRUE(
-        TextFormat::ParseFromString(nested_message_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(nested_message_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              0);
-  }
-  {
-    no_op_fields = {};
     const absl::string_view foreign_message_parse_string =
         "optional_foreign_message { c: 0 } ";
     EXPECT_TRUE(
         TextFormat::ParseFromString(foreign_message_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(foreign_message_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(foreign_message_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view nested_enum_parse_string =
         "optional_nested_enum: ZERO ";
     EXPECT_TRUE(TextFormat::ParseFromString(nested_enum_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(nested_enum_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(nested_enum_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view foreign_enum_parse_string =
         "optional_foreign_enum: FOREIGN_ZERO ";
     EXPECT_TRUE(TextFormat::ParseFromString(foreign_enum_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(foreign_enum_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(foreign_enum_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view string_piece_parse_string =
         "optional_string_piece: '' ";
     EXPECT_TRUE(TextFormat::ParseFromString(string_piece_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(string_piece_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(string_piece_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     const absl::string_view cord_parse_string = "optional_cord: '' ";
     EXPECT_TRUE(TextFormat::ParseFromString(cord_parse_string, &proto));
-    EXPECT_TRUE(parser.ParseFromString(cord_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
+    EXPECT_FALSE(parser.ParseFromString(cord_parse_string, &proto));
   }
   {
-    no_op_fields = {};
     // Sanity check that repeated fields work the same.
     const absl::string_view repeated_int32_parse_string = "repeated_int32: 0 ";
     EXPECT_TRUE(
         TextFormat::ParseFromString(repeated_int32_parse_string, &proto));
     EXPECT_TRUE(parser.ParseFromString(repeated_int32_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              0);
   }
   {
-    no_op_fields = {};
     const absl::string_view repeated_bool_parse_string =
         "repeated_bool: false  ";
     EXPECT_TRUE(
         TextFormat::ParseFromString(repeated_bool_parse_string, &proto));
     EXPECT_TRUE(parser.ParseFromString(repeated_bool_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              0);
   }
   {
-    no_op_fields = {};
     const absl::string_view repeated_string_parse_string =
         "repeated_string: '' ";
     EXPECT_TRUE(
         TextFormat::ParseFromString(repeated_string_parse_string, &proto));
     EXPECT_TRUE(parser.ParseFromString(repeated_string_parse_string, &proto));
-    EXPECT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              0);
-  }
-}
-
-TEST_F(TextFormatTest, FieldsPopulatedCorrectly) {
-  proto3_unittest::TestAllTypes proto;
-  TextFormat::Parser parser;
-  TextFormat::Parser::UnsetFieldsMetadata no_op_fields;
-  parser.OutputNoOpFields(&no_op_fields);
-  {
-    no_op_fields = {};
-    const absl::string_view parse_string = R"pb(
-      optional_int32: 0
-      optional_uint32: 10
-      optional_nested_message { bb: 0 }
-    )pb";
-    EXPECT_TRUE(parser.ParseFromString(parse_string, &proto));
-    ASSERT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              2);
-    std::vector<const void*> ptrs =
-        UnsetFieldsMetadataTextFormatTestUtil::GetRawAddresses(no_op_fields);
-    EXPECT_EQ(*static_cast<const int32_t*>(ptrs[0]), 0);
-    EXPECT_EQ(*static_cast<const int32_t*>(ptrs[1]), 0);
-    proto.set_optional_int32(20);
-    proto.mutable_optional_nested_message()->set_bb(30);
-    const std::vector<int32_t> new_values{
-        *static_cast<const int32_t*>(ptrs[0]),
-        *static_cast<const int32_t*>(ptrs[1])};
-    EXPECT_THAT(new_values, testing::UnorderedElementsAre(20, 30));
-  }
-  {
-    no_op_fields = {};
-    const absl::string_view parse_string = R"pb(
-      optional_bool: false
-      optional_uint32: 10
-      optional_nested_message { bb: 20 }
-    )pb";
-    EXPECT_TRUE(parser.ParseFromString(parse_string, &proto));
-    ASSERT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
-    std::vector<const void*> ptrs =
-        UnsetFieldsMetadataTextFormatTestUtil::GetRawAddresses(no_op_fields);
-    EXPECT_EQ(*static_cast<const bool*>(ptrs[0]), false);
-    proto.set_optional_bool(true);
-    EXPECT_EQ(*static_cast<const bool*>(ptrs[0]), true);
-  }
-  {
-    // The address returned by the field is a string_view, which is a separate
-    // alocation. Check address directly.
-    no_op_fields = {};
-    const absl::string_view parse_string = "optional_string: \"\"";
-    EXPECT_TRUE(parser.ParseFromString(parse_string, &proto));
-    ASSERT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
-    const Reflection* reflection = proto.GetReflection();
-    const FieldDescriptor* field = proto.GetDescriptor()->FindFieldByNumber(14);
-    EXPECT_EQ(
-        UnsetFieldsMetadataTextFormatTestUtil::GetRawAddresses(no_op_fields)[0],
-        UnsetFieldsMetadataTextFormatTestUtil::GetAddress(proto, *reflection,
-                                                          *field));
-  }
-  {
-    // The address returned by the field is a string_view, which is a separate
-    // alocation. Check address directly.
-    no_op_fields = {};
-    const absl::string_view parse_string = "optional_bytes: \"\"";
-    EXPECT_TRUE(parser.ParseFromString(parse_string, &proto));
-    ASSERT_EQ(UnsetFieldsMetadataTextFormatTestUtil::NumFields(no_op_fields),
-              1);
-    const Reflection* reflection = proto.GetReflection();
-    const FieldDescriptor* field = proto.GetDescriptor()->FindFieldByNumber(15);
-    EXPECT_EQ(
-        UnsetFieldsMetadataTextFormatTestUtil::GetRawAddresses(no_op_fields)[0],
-        UnsetFieldsMetadataTextFormatTestUtil::GetAddress(proto, *reflection,
-                                                          *field));
   }
 }
 
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index df0311c..853d5da 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -696,7 +696,7 @@
       // we are merely checking for a difference in field values,
       // rather than the addition or deletion of fields).
       std::vector<const FieldDescriptor*> fields_union =
-          CombineFields(message1, message1_fields, FULL, message2_fields, FULL);
+          CombineFields(message1_fields, FULL, message2_fields, FULL);
       return CompareWithFieldsInternal(message1, message2, unpacked_any,
                                        fields_union, fields_union,
                                        parent_fields);
@@ -719,8 +719,8 @@
       // but only the intersection for message2.  This way, any fields
       // only present in message2 will be ignored, but any fields only
       // present in message1 will be marked as a difference.
-      std::vector<const FieldDescriptor*> fields_intersection = CombineFields(
-          message1, message1_fields, PARTIAL, message2_fields, PARTIAL);
+      std::vector<const FieldDescriptor*> fields_intersection =
+          CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL);
       return CompareWithFieldsInternal(message1, message2, unpacked_any,
                                        message1_fields, fields_intersection,
                                        parent_fields);
@@ -728,48 +728,9 @@
   }
 }
 
-namespace {
-bool ValidMissingField(const FieldDescriptor& f) {
-  switch (f.cpp_type()) {
-    case FieldDescriptor::CPPTYPE_INT32:
-    case FieldDescriptor::CPPTYPE_UINT32:
-    case FieldDescriptor::CPPTYPE_INT64:
-    case FieldDescriptor::CPPTYPE_UINT64:
-    case FieldDescriptor::CPPTYPE_FLOAT:
-    case FieldDescriptor::CPPTYPE_DOUBLE:
-    case FieldDescriptor::CPPTYPE_STRING:
-    case FieldDescriptor::CPPTYPE_BOOL:
-    case FieldDescriptor::CPPTYPE_ENUM:
-      return true;
-    default:
-      return false;
-  }
-}
-}  // namespace
-
-bool MessageDifferencer::ShouldCompareNoPresence(
-    const Message& message1, const Reflection& reflection1,
-    const FieldDescriptor* field2) const {
-  const bool compare_no_presence_by_field = force_compare_no_presence_ &&
-                                            !field2->has_presence() &&
-                                            !field2->is_repeated();
-  if (compare_no_presence_by_field) {
-    return true;
-  }
-  const bool compare_no_presence_by_address =
-      !field2->is_repeated() && !field2->has_presence() &&
-      ValidMissingField(*field2) &&
-      require_no_presence_fields_.addresses_.contains(
-          TextFormat::Parser::UnsetFieldsMetadata::GetUnsetFieldAddress(
-              message1, reflection1, *field2));
-  return compare_no_presence_by_address;
-}
-
 std::vector<const FieldDescriptor*> MessageDifferencer::CombineFields(
-    const Message& message1, const std::vector<const FieldDescriptor*>& fields1,
-    Scope fields1_scope, const std::vector<const FieldDescriptor*>& fields2,
-    Scope fields2_scope) {
-  const Reflection* reflection1 = message1.GetReflection();
+    const std::vector<const FieldDescriptor*>& fields1, Scope fields1_scope,
+    const std::vector<const FieldDescriptor*>& fields2, Scope fields2_scope) {
   size_t index1 = 0;
   size_t index2 = 0;
 
@@ -787,8 +748,8 @@
     } else if (FieldBefore(field2, field1)) {
       if (fields2_scope == FULL) {
         tmp_message_fields_.push_back(field2);
-      } else if (fields2_scope == PARTIAL &&
-                 ShouldCompareNoPresence(message1, *reflection1, field2)) {
+      } else if (fields2_scope == PARTIAL && force_compare_no_presence_ &&
+                 !field2->has_presence() && !field2->is_repeated()) {
         // In order to make MessageDifferencer play nicely with no-presence
         // fields in unit tests, we want to check if the expected proto
         // (message1) has some fields which are set to their default value but
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 6d8e9a9..5c058f9 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -32,7 +32,6 @@
 #include "absl/log/absl_check.h"
 #include "google/protobuf/descriptor.h"  // FieldDescriptor
 #include "google/protobuf/message.h"     // Message
-#include "google/protobuf/text_format.h"
 #include "google/protobuf/unknown_field_set.h"
 #include "google/protobuf/util/field_comparator.h"
 
@@ -582,13 +581,6 @@
   // in the comparison.
   void set_force_compare_no_presence(bool value);
 
-  // If set, the fields in message1 that equal the fields passed here will be
-  // treated as required for comparison, even if they are absent.
-  void set_require_no_presence_fields(
-      const google::protobuf::TextFormat::Parser::UnsetFieldsMetadata& fields) {
-    require_no_presence_fields_ = fields;
-  }
-
   // DEPRECATED. Pass a DefaultFieldComparator instance instead.
   // Sets the type of comparison (as defined in the FloatComparison enumeration
   // above) that is used by this differencer when comparing float (and double)
@@ -776,7 +768,6 @@
   // list.  Fields only present in one of the lists will only appear in the
   // combined list if the corresponding fields_scope option is set to FULL.
   std::vector<const FieldDescriptor*> CombineFields(
-      const Message& message1,
       const std::vector<const FieldDescriptor*>& fields1, Scope fields1_scope,
       const std::vector<const FieldDescriptor*>& fields2, Scope fields2_scope);
 
@@ -928,17 +919,11 @@
       const FieldDescriptor* field,
       const RepeatedFieldComparison& new_comparison);
 
-  // Whether we should still compare the field despite its absence in message1.
-  bool ShouldCompareNoPresence(const Message& message1,
-                               const Reflection& reflection1,
-                               const FieldDescriptor* field2) const;
-
   Reporter* reporter_;
   DefaultFieldComparator default_field_comparator_;
   MessageFieldComparison message_field_comparison_;
   Scope scope_;
   absl::flat_hash_set<const FieldDescriptor*> force_compare_no_presence_fields_;
-  google::protobuf::TextFormat::Parser::UnsetFieldsMetadata require_no_presence_fields_;
   absl::flat_hash_set<std::string> force_compare_failure_triggering_fields_;
   RepeatedFieldComparison repeated_field_comparison_;
 
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 191281a..e673d02 100644
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -29,10 +29,8 @@
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/any_test.pb.h"
-#include "google/protobuf/descriptor.h"
 #include "google/protobuf/map_test_util.h"
 #include "google/protobuf/map_unittest.pb.h"
-#include "google/protobuf/message.h"
 #include "google/protobuf/test_util.h"
 #include "google/protobuf/text_format.h"
 #include "google/protobuf/unittest.pb.h"
@@ -46,31 +44,12 @@
 namespace google {
 namespace protobuf {
 
-namespace internal {
-class UnsetFieldsMetadataMessageDifferencerTestUtil {
- public:
-  static void AddExplicitUnsetField(
-      const Message& message, const Reflection& reflection,
-      const FieldDescriptor& fd,
-      TextFormat::Parser::UnsetFieldsMetadata* metadata) {
-    metadata->addresses_.insert(
-        TextFormat::Parser::UnsetFieldsMetadata::GetUnsetFieldAddress(
-            message, reflection, fd));
-  }
-};
-}  // namespace internal
-
 namespace {
 
-using ::google::protobuf::internal::UnsetFieldsMetadataMessageDifferencerTestUtil;
-
 
 proto3_unittest::TestNoPresenceField MakeTestNoPresenceField() {
   proto3_unittest::TestNoPresenceField msg1, msg2;
   msg1.set_no_presence_bool(true);
-  msg1.set_no_presence_bool2(true);
-  msg1.set_no_presence_bool3(true);
-  msg1.set_no_presence_string("yolo");
   msg2 = msg1;
   *msg1.mutable_no_presence_nested() = msg2;
   *msg1.add_no_presence_repeated_nested() = msg2;
@@ -400,212 +379,6 @@
 }
 
 TEST(MessageDifferencerTest,
-     PartialEqualityTestBooleanPresenceFieldMissingWithAddress) {
-  util::MessageDifferencer address_differencer;
-  address_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-
-  // This differencer is not setting force_compare_no_presence.
-  util::MessageDifferencer default_differencer;
-  default_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-  default_differencer.set_force_compare_no_presence(false);
-
-  // When clearing a singular no presence field, it will be included in the
-  // comparison.
-  proto3_unittest::TestNoPresenceField msg1 = MakeTestNoPresenceField();
-  proto3_unittest::TestNoPresenceField msg2 = MakeTestNoPresenceField();
-
-  const Reflection* reflection1 = msg1.GetReflection();
-  const FieldDescriptor* fd1 = msg1.GetDescriptor()->FindFieldByNumber(1);
-  TextFormat::Parser::UnsetFieldsMetadata metadata;
-  UnsetFieldsMetadataMessageDifferencerTestUtil::AddExplicitUnsetField(
-      msg1, *reflection1, *fd1, &metadata);
-  address_differencer.set_require_no_presence_fields(metadata);
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.clear_no_presence_bool();
-
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg2.clear_no_presence_bool();
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.set_no_presence_bool(true);
-
-  EXPECT_FALSE(default_differencer.Compare(msg1, msg2));
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-}
-
-TEST(MessageDifferencerTest,
-     PartialEqualityTestStringPresenceFieldMissingWithAddress) {
-  util::MessageDifferencer address_differencer;
-  address_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-
-  // This differencer is not setting force_compare_no_presence.
-  util::MessageDifferencer default_differencer;
-  default_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-  default_differencer.set_force_compare_no_presence(false);
-
-  // When clearing a singular no presence field, it will be included in the
-  // comparison.
-  proto3_unittest::TestNoPresenceField msg1 = MakeTestNoPresenceField();
-  proto3_unittest::TestNoPresenceField msg2 = MakeTestNoPresenceField();
-
-  const Reflection* reflection1 = msg1.GetReflection();
-  const FieldDescriptor* fd1 = msg1.GetDescriptor()->FindFieldByNumber(4);
-  TextFormat::Parser::UnsetFieldsMetadata metadata;
-  UnsetFieldsMetadataMessageDifferencerTestUtil::AddExplicitUnsetField(
-      msg1, *reflection1, *fd1, &metadata);
-  address_differencer.set_require_no_presence_fields(metadata);
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.clear_no_presence_string();
-
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg2.clear_no_presence_string();
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.set_no_presence_string("yolo");
-
-  EXPECT_FALSE(default_differencer.Compare(msg1, msg2));
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-}
-
-// Ensure multiple booleans are addressed distinctly. This is trivially the case
-// now, but tests against possible optimizations in the future to use bitfields.
-TEST(MessageDifferencerTest,
-     PartialEqualityTestTwoBoolsPresenceFieldMissingWithAddress) {
-  util::MessageDifferencer address_differencer;
-  address_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-
-  // This differencer is not setting force_compare_no_presence.
-  util::MessageDifferencer default_differencer;
-  default_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-  default_differencer.set_force_compare_no_presence(false);
-
-  // When clearing a singular no presence field, it will be included in the
-  // comparison.
-  proto3_unittest::TestNoPresenceField msg1 = MakeTestNoPresenceField();
-  proto3_unittest::TestNoPresenceField msg2 = MakeTestNoPresenceField();
-
-  const Reflection* reflection1 = msg1.GetReflection();
-  const FieldDescriptor* fd1 = msg1.GetDescriptor()->FindFieldByNumber(5);
-  TextFormat::Parser::UnsetFieldsMetadata metadata;
-  UnsetFieldsMetadataMessageDifferencerTestUtil::AddExplicitUnsetField(
-      msg1, *reflection1, *fd1, &metadata);
-  address_differencer.set_require_no_presence_fields(metadata);
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  // Trigger on bool2.
-  msg1.clear_no_presence_bool2();
-
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  // Triggering on bool2 still ignores bool3.
-  msg1.set_no_presence_bool2(true);
-  msg1.clear_no_presence_bool3();
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-}
-
-TEST(MessageDifferencerTest,
-     PartialEqualityTestBooleanNestedMessagePresenceFieldMissingWithAddress) {
-  util::MessageDifferencer address_differencer;
-  address_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-
-  // This differencer is not setting force_compare_no_presence.
-  util::MessageDifferencer default_differencer;
-  default_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-  default_differencer.set_force_compare_no_presence(false);
-
-  // When clearing a singular no presence field, it will be included in the
-  // comparison.
-  proto3_unittest::TestNoPresenceField msg1 = MakeTestNoPresenceField();
-  proto3_unittest::TestNoPresenceField msg2 = MakeTestNoPresenceField();
-
-  const Reflection* reflection1 = msg1.no_presence_nested().GetReflection();
-  const FieldDescriptor* fd1 = msg1.GetDescriptor()->FindFieldByNumber(1);
-  TextFormat::Parser::UnsetFieldsMetadata metadata;
-  UnsetFieldsMetadataMessageDifferencerTestUtil::AddExplicitUnsetField(
-      msg1.no_presence_nested(), *reflection1, *fd1, &metadata);
-  address_differencer.set_require_no_presence_fields(metadata);
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.mutable_no_presence_nested()->clear_no_presence_bool();
-
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg2.mutable_no_presence_nested()->clear_no_presence_bool();
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.mutable_no_presence_nested()->set_no_presence_bool(true);
-
-  EXPECT_FALSE(default_differencer.Compare(msg1, msg2));
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-}
-
-TEST(MessageDifferencerTest,
-     PartialEqualityTestBooleanRepeatedMessagePresenceFieldMissingWithAddress) {
-  util::MessageDifferencer address_differencer;
-  address_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-
-  // This differencer is not setting force_compare_no_presence.
-  util::MessageDifferencer default_differencer;
-  default_differencer.set_scope(util::MessageDifferencer::PARTIAL);
-  default_differencer.set_force_compare_no_presence(false);
-
-  // When clearing a singular no presence field, it will be included in the
-  // comparison.
-  proto3_unittest::TestNoPresenceField msg1 = MakeTestNoPresenceField();
-  proto3_unittest::TestNoPresenceField msg2 = MakeTestNoPresenceField();
-
-  const Reflection* reflection1 =
-      msg1.no_presence_repeated_nested(0).GetReflection();
-  const FieldDescriptor* fd1 = msg1.GetDescriptor()->FindFieldByNumber(1);
-  TextFormat::Parser::UnsetFieldsMetadata metadata;
-  UnsetFieldsMetadataMessageDifferencerTestUtil::AddExplicitUnsetField(
-      msg1.no_presence_repeated_nested(0), *reflection1, *fd1, &metadata);
-  address_differencer.set_require_no_presence_fields(metadata);
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.mutable_no_presence_repeated_nested(0)->clear_no_presence_bool();
-
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg2.mutable_no_presence_repeated_nested(0)->clear_no_presence_bool();
-
-  EXPECT_TRUE(address_differencer.Compare(msg1, msg2));
-  EXPECT_TRUE(default_differencer.Compare(msg1, msg2));
-
-  msg1.mutable_no_presence_repeated_nested(0)->set_no_presence_bool(true);
-
-  EXPECT_FALSE(default_differencer.Compare(msg1, msg2));
-  EXPECT_FALSE(address_differencer.Compare(msg1, msg2));
-}
-
-TEST(MessageDifferencerTest,
      PartialEqualityTestExtraFieldNoPresenceForceCompareReporterAware) {
   std::string output;
   // Before we can check the output string, we must make sure the
diff --git a/src/google/protobuf/util/message_differencer_unittest_proto3.proto b/src/google/protobuf/util/message_differencer_unittest_proto3.proto
index b139554..55540ce 100644
--- a/src/google/protobuf/util/message_differencer_unittest_proto3.proto
+++ b/src/google/protobuf/util/message_differencer_unittest_proto3.proto
@@ -18,7 +18,4 @@
   bool no_presence_bool = 1;
   TestNoPresenceField no_presence_nested = 2;
   repeated TestNoPresenceField no_presence_repeated_nested = 3;
-  string no_presence_string = 4;
-  bool no_presence_bool2 = 5;
-  bool no_presence_bool3 = 6;
 }