google-protobuf 3.11.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

File without changes
@@ -100,11 +100,11 @@ static VALUE table_key(Map* self, VALUE key,
100
100
  return key;
101
101
  }
102
102
 
103
- static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
103
+ static VALUE table_key_to_ruby(Map* self, upb_strview key) {
104
104
  switch (self->key_type) {
105
105
  case UPB_TYPE_BYTES:
106
106
  case UPB_TYPE_STRING: {
107
- VALUE ret = rb_str_new(buf, length);
107
+ VALUE ret = rb_str_new(key.data, key.size);
108
108
  rb_enc_associate(ret,
109
109
  (self->key_type == UPB_TYPE_BYTES) ?
110
110
  kRubyString8bitEncoding : kRubyStringUtf8Encoding);
@@ -116,7 +116,7 @@ static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
116
116
  case UPB_TYPE_INT64:
117
117
  case UPB_TYPE_UINT32:
118
118
  case UPB_TYPE_UINT64:
119
- return native_slot_get(self->key_type, Qnil, buf);
119
+ return native_slot_get(self->key_type, Qnil, key.data);
120
120
 
121
121
  default:
122
122
  assert(false);
@@ -289,9 +289,7 @@ VALUE Map_each(VALUE _self) {
289
289
  for (upb_strtable_begin(&it, &self->table);
290
290
  !upb_strtable_done(&it);
291
291
  upb_strtable_next(&it)) {
292
-
293
- VALUE key = table_key_to_ruby(
294
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
292
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
295
293
 
296
294
  upb_value v = upb_strtable_iter_value(&it);
297
295
  void* mem = value_memory(&v);
@@ -319,9 +317,7 @@ VALUE Map_keys(VALUE _self) {
319
317
  for (upb_strtable_begin(&it, &self->table);
320
318
  !upb_strtable_done(&it);
321
319
  upb_strtable_next(&it)) {
322
-
323
- VALUE key = table_key_to_ruby(
324
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
320
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
325
321
 
326
322
  rb_ary_push(ret, key);
327
323
  }
@@ -526,17 +522,14 @@ VALUE Map_dup(VALUE _self) {
526
522
  for (upb_strtable_begin(&it, &self->table);
527
523
  !upb_strtable_done(&it);
528
524
  upb_strtable_next(&it)) {
529
-
525
+ upb_strview k = upb_strtable_iter_key(&it);
530
526
  upb_value v = upb_strtable_iter_value(&it);
531
527
  void* mem = value_memory(&v);
532
528
  upb_value dup;
533
529
  void* dup_mem = value_memory(&dup);
534
530
  native_slot_dup(self->value_type, dup_mem, mem);
535
531
 
536
- if (!upb_strtable_insert2(&new_self->table,
537
- upb_strtable_iter_key(&it),
538
- upb_strtable_iter_keylength(&it),
539
- dup)) {
532
+ if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
540
533
  rb_raise(rb_eRuntimeError, "Error inserting value into new table");
541
534
  }
542
535
  }
@@ -554,7 +547,7 @@ VALUE Map_deep_copy(VALUE _self) {
554
547
  for (upb_strtable_begin(&it, &self->table);
555
548
  !upb_strtable_done(&it);
556
549
  upb_strtable_next(&it)) {
557
-
550
+ upb_strview k = upb_strtable_iter_key(&it);
558
551
  upb_value v = upb_strtable_iter_value(&it);
559
552
  void* mem = value_memory(&v);
560
553
  upb_value dup;
@@ -562,10 +555,7 @@ VALUE Map_deep_copy(VALUE _self) {
562
555
  native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
563
556
  mem);
564
557
 
565
- if (!upb_strtable_insert2(&new_self->table,
566
- upb_strtable_iter_key(&it),
567
- upb_strtable_iter_keylength(&it),
568
- dup)) {
558
+ if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
569
559
  rb_raise(rb_eRuntimeError, "Error inserting value into new table");
570
560
  }
571
561
  }
@@ -618,16 +608,13 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
618
608
  for (upb_strtable_begin(&it, &self->table);
619
609
  !upb_strtable_done(&it);
620
610
  upb_strtable_next(&it)) {
621
-
611
+ upb_strview k = upb_strtable_iter_key(&it);
622
612
  upb_value v = upb_strtable_iter_value(&it);
623
613
  void* mem = value_memory(&v);
624
614
  upb_value other_v;
625
615
  void* other_mem = value_memory(&other_v);
626
616
 
627
- if (!upb_strtable_lookup2(&other->table,
628
- upb_strtable_iter_key(&it),
629
- upb_strtable_iter_keylength(&it),
630
- &other_v)) {
617
+ if (!upb_strtable_lookup2(&other->table, k.data, k.size, &other_v)) {
631
618
  // Not present in other map.
632
619
  return Qfalse;
633
620
  }
@@ -655,11 +642,9 @@ VALUE Map_hash(VALUE _self) {
655
642
  VALUE hash_sym = rb_intern("hash");
656
643
 
657
644
  upb_strtable_iter it;
658
- for (upb_strtable_begin(&it, &self->table);
659
- !upb_strtable_done(&it);
645
+ for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
660
646
  upb_strtable_next(&it)) {
661
- VALUE key = table_key_to_ruby(
662
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
647
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
663
648
 
664
649
  upb_value v = upb_strtable_iter_value(&it);
665
650
  void* mem = value_memory(&v);
@@ -687,8 +672,7 @@ VALUE Map_to_h(VALUE _self) {
687
672
  for (upb_strtable_begin(&it, &self->table);
688
673
  !upb_strtable_done(&it);
689
674
  upb_strtable_next(&it)) {
690
- VALUE key = table_key_to_ruby(
691
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
675
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
692
676
  upb_value v = upb_strtable_iter_value(&it);
693
677
  void* mem = value_memory(&v);
694
678
  VALUE value = native_slot_get(self->value_type,
@@ -720,11 +704,9 @@ VALUE Map_inspect(VALUE _self) {
720
704
  VALUE inspect_sym = rb_intern("inspect");
721
705
 
722
706
  upb_strtable_iter it;
723
- for (upb_strtable_begin(&it, &self->table);
724
- !upb_strtable_done(&it);
707
+ for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
725
708
  upb_strtable_next(&it)) {
726
- VALUE key = table_key_to_ruby(
727
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
709
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
728
710
 
729
711
  upb_value v = upb_strtable_iter_value(&it);
730
712
  void* mem = value_memory(&v);
@@ -785,20 +767,15 @@ VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
785
767
  for (upb_strtable_begin(&it, &other->table);
786
768
  !upb_strtable_done(&it);
787
769
  upb_strtable_next(&it)) {
770
+ upb_strview k = upb_strtable_iter_key(&it);
788
771
 
789
772
  // Replace any existing value by issuing a 'remove' operation first.
790
773
  upb_value v;
791
774
  upb_value oldv;
792
- upb_strtable_remove2(&self->table,
793
- upb_strtable_iter_key(&it),
794
- upb_strtable_iter_keylength(&it),
795
- &oldv);
775
+ upb_strtable_remove2(&self->table, k.data, k.size, &oldv);
796
776
 
797
777
  v = upb_strtable_iter_value(&it);
798
- upb_strtable_insert2(&self->table,
799
- upb_strtable_iter_key(&it),
800
- upb_strtable_iter_keylength(&it),
801
- v);
778
+ upb_strtable_insert2(&self->table, k.data, k.size, v);
802
779
  }
803
780
  } else {
804
781
  rb_raise(rb_eArgError, "Unknown type merging into Map");
@@ -822,10 +799,7 @@ bool Map_done(Map_iter* iter) {
822
799
  }
823
800
 
824
801
  VALUE Map_iter_key(Map_iter* iter) {
825
- return table_key_to_ruby(
826
- iter->self,
827
- upb_strtable_iter_key(&iter->it),
828
- upb_strtable_iter_keylength(&iter->it));
802
+ return table_key_to_ruby(iter->self, upb_strtable_iter_key(&iter->it));
829
803
  }
830
804
 
831
805
  VALUE Map_iter_value(Map_iter* iter) {
@@ -242,9 +242,14 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
242
242
  // Method calls like 'has_foo?' are not allowed if field "foo" does not have
243
243
  // a hasbit (e.g. repeated fields or non-message type fields for proto3
244
244
  // syntax).
245
- if (accessor_type == METHOD_PRESENCE && test_f != NULL &&
246
- !upb_fielddef_haspresence(test_f)) {
247
- return METHOD_UNKNOWN;
245
+ if (accessor_type == METHOD_PRESENCE && test_f != NULL) {
246
+ if (!upb_fielddef_haspresence(test_f)) return METHOD_UNKNOWN;
247
+
248
+ // TODO(haberman): remove this case, allow for proto3 oneofs.
249
+ if (upb_fielddef_realcontainingoneof(test_f) &&
250
+ upb_filedef_syntax(upb_fielddef_file(test_f)) == UPB_SYNTAX_PROTO3) {
251
+ return METHOD_UNKNOWN;
252
+ }
248
253
  }
249
254
 
250
255
  *o = test_o;
@@ -605,11 +610,17 @@ VALUE Message_inspect(VALUE _self) {
605
610
  */
606
611
  VALUE Message_to_h(VALUE _self) {
607
612
  MessageHeader* self;
608
- VALUE hash;
613
+ VALUE hash = rb_hash_new();
609
614
  upb_msg_field_iter it;
615
+ bool is_proto2;
610
616
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
611
617
 
612
- hash = rb_hash_new();
618
+ // We currently have a few behaviors that are specific to proto2.
619
+ // This is unfortunate, we should key behaviors off field attributes (like
620
+ // whether a field has presence), not proto2 vs. proto3. We should see if we
621
+ // can change this without breaking users.
622
+ is_proto2 =
623
+ upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2;
613
624
 
614
625
  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
615
626
  !upb_msg_field_done(&it);
@@ -618,10 +629,9 @@ VALUE Message_to_h(VALUE _self) {
618
629
  VALUE msg_value;
619
630
  VALUE msg_key;
620
631
 
621
- // For proto2, do not include fields which are not set.
622
- if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
623
- field_contains_hasbit(self->descriptor->layout, field) &&
624
- !layout_has(self->descriptor->layout, Message_data(self), field)) {
632
+ // Do not include fields that are not present (oneof or optional fields).
633
+ if (is_proto2 && upb_fielddef_haspresence(field) &&
634
+ !layout_has(self->descriptor->layout, Message_data(self), field)) {
625
635
  continue;
626
636
  }
627
637
 
@@ -631,8 +641,7 @@ VALUE Message_to_h(VALUE _self) {
631
641
  msg_value = Map_to_h(msg_value);
632
642
  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
633
643
  msg_value = RepeatedField_to_ary(msg_value);
634
- if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
635
- RARRAY_LEN(msg_value) == 0) {
644
+ if (is_proto2 && RARRAY_LEN(msg_value) == 0) {
636
645
  continue;
637
646
  }
638
647
 
@@ -285,6 +285,7 @@ VALUE MessageBuilderContext_initialize(VALUE _self,
285
285
  VALUE _file_builder,
286
286
  VALUE name);
287
287
  VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
288
+ VALUE MessageBuilderContext_proto3_optional(int argc, VALUE* argv, VALUE _self);
288
289
  VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self);
289
290
  VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self);
290
291
  VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self);
@@ -496,11 +496,14 @@ void create_layout(Descriptor* desc) {
496
496
  const upb_msgdef *msgdef = desc->msgdef;
497
497
  MessageLayout* layout = ALLOC(MessageLayout);
498
498
  int nfields = upb_msgdef_numfields(msgdef);
499
- int noneofs = upb_msgdef_numoneofs(msgdef);
499
+ int noneofs = upb_msgdef_numrealoneofs(msgdef);
500
500
  upb_msg_field_iter it;
501
501
  upb_msg_oneof_iter oit;
502
502
  size_t off = 0;
503
503
  size_t hasbit = 0;
504
+ int i;
505
+
506
+ (void)i;
504
507
 
505
508
  layout->empty_template = NULL;
506
509
  layout->desc = desc;
@@ -513,11 +516,22 @@ void create_layout(Descriptor* desc) {
513
516
  layout->oneofs = ALLOC_N(MessageOneof, noneofs);
514
517
  }
515
518
 
519
+ #ifndef NDEBUG
520
+ for (i = 0; i < nfields; i++) {
521
+ layout->fields[i].offset = -1;
522
+ }
523
+
524
+ for (i = 0; i < noneofs; i++) {
525
+ layout->oneofs[i].offset = -1;
526
+ }
527
+ #endif
528
+
516
529
  for (upb_msg_field_begin(&it, msgdef);
517
530
  !upb_msg_field_done(&it);
518
531
  upb_msg_field_next(&it)) {
519
532
  const upb_fielddef* field = upb_msg_iter_field(&it);
520
- if (upb_fielddef_haspresence(field)) {
533
+ if (upb_fielddef_haspresence(field) &&
534
+ !upb_fielddef_realcontainingoneof(field)) {
521
535
  layout->fields[upb_fielddef_index(field)].hasbit = hasbit++;
522
536
  } else {
523
537
  layout->fields[upb_fielddef_index(field)].hasbit =
@@ -540,7 +554,7 @@ void create_layout(Descriptor* desc) {
540
554
  !upb_msg_field_done(&it);
541
555
  upb_msg_field_next(&it)) {
542
556
  const upb_fielddef* field = upb_msg_iter_field(&it);
543
- if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) ||
557
+ if (upb_fielddef_realcontainingoneof(field) || !upb_fielddef_isseq(field) ||
544
558
  upb_fielddef_ismap(field)) {
545
559
  continue;
546
560
  }
@@ -555,7 +569,7 @@ void create_layout(Descriptor* desc) {
555
569
  !upb_msg_field_done(&it);
556
570
  upb_msg_field_next(&it)) {
557
571
  const upb_fielddef* field = upb_msg_iter_field(&it);
558
- if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) ||
572
+ if (upb_fielddef_realcontainingoneof(field) || !upb_fielddef_isseq(field) ||
559
573
  !upb_fielddef_ismap(field)) {
560
574
  continue;
561
575
  }
@@ -572,7 +586,7 @@ void create_layout(Descriptor* desc) {
572
586
  !upb_msg_field_done(&it);
573
587
  upb_msg_field_next(&it)) {
574
588
  const upb_fielddef* field = upb_msg_iter_field(&it);
575
- if (upb_fielddef_containingoneof(field) || !is_value_field(field) ||
589
+ if (upb_fielddef_realcontainingoneof(field) || !is_value_field(field) ||
576
590
  upb_fielddef_isseq(field)) {
577
591
  continue;
578
592
  }
@@ -589,7 +603,7 @@ void create_layout(Descriptor* desc) {
589
603
  const upb_fielddef* field = upb_msg_iter_field(&it);
590
604
  size_t field_size;
591
605
 
592
- if (upb_fielddef_containingoneof(field) || is_value_field(field)) {
606
+ if (upb_fielddef_realcontainingoneof(field) || is_value_field(field)) {
593
607
  continue;
594
608
  }
595
609
 
@@ -624,6 +638,10 @@ void create_layout(Descriptor* desc) {
624
638
  // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
625
639
  // all fields.
626
640
  size_t field_size = NATIVE_SLOT_MAX_SIZE;
641
+
642
+ if (upb_oneofdef_issynthetic(oneof)) continue;
643
+ assert(upb_oneofdef_index(oneof) < noneofs);
644
+
627
645
  // Align the offset.
628
646
  off = align_up_to(off, field_size);
629
647
  // Assign all fields in the oneof this same offset.
@@ -643,6 +661,8 @@ void create_layout(Descriptor* desc) {
643
661
  upb_msg_oneof_next(&oit)) {
644
662
  const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
645
663
  size_t field_size = sizeof(uint32_t);
664
+ if (upb_oneofdef_issynthetic(oneof)) continue;
665
+ assert(upb_oneofdef_index(oneof) < noneofs);
646
666
  // Align the offset.
647
667
  off = (off + field_size - 1) & ~(field_size - 1);
648
668
  layout->oneofs[upb_oneofdef_index(oneof)].case_offset = off;
@@ -652,6 +672,16 @@ void create_layout(Descriptor* desc) {
652
672
  layout->size = off;
653
673
  layout->msgdef = msgdef;
654
674
 
675
+ #ifndef NDEBUG
676
+ for (i = 0; i < nfields; i++) {
677
+ assert(layout->fields[i].offset != -1);
678
+ }
679
+
680
+ for (i = 0; i < noneofs; i++) {
681
+ assert(layout->oneofs[i].offset != -1);
682
+ }
683
+ #endif
684
+
655
685
  // Create the empty message template.
656
686
  layout->empty_template = ALLOC_N(char, layout->size);
657
687
  memset(layout->empty_template, 0, layout->size);
@@ -725,10 +755,7 @@ static bool slot_is_hasbit_set(MessageLayout* layout,
725
755
  const void* storage,
726
756
  const upb_fielddef* field) {
727
757
  size_t hasbit = layout->fields[upb_fielddef_index(field)].hasbit;
728
- if (hasbit == MESSAGE_FIELD_NO_HASBIT) {
729
- return false;
730
- }
731
-
758
+ assert(field_contains_hasbit(layout, field));
732
759
  return DEREF_OFFSET(
733
760
  (uint8_t*)storage, hasbit / 8, char) & (1 << (hasbit % 8));
734
761
  }
@@ -736,15 +763,21 @@ static bool slot_is_hasbit_set(MessageLayout* layout,
736
763
  VALUE layout_has(MessageLayout* layout,
737
764
  const void* storage,
738
765
  const upb_fielddef* field) {
739
- assert(field_contains_hasbit(layout, field));
740
- return slot_is_hasbit_set(layout, storage, field) ? Qtrue : Qfalse;
766
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
767
+ assert(upb_fielddef_haspresence(field));
768
+ if (oneof) {
769
+ uint32_t oneof_case = slot_read_oneof_case(layout, storage, oneof);
770
+ return oneof_case == upb_fielddef_number(field) ? Qtrue : Qfalse;
771
+ } else {
772
+ return slot_is_hasbit_set(layout, storage, field) ? Qtrue : Qfalse;
773
+ }
741
774
  }
742
775
 
743
776
  void layout_clear(MessageLayout* layout,
744
777
  const void* storage,
745
778
  const upb_fielddef* field) {
746
779
  void* memory = slot_memory(layout, storage, field);
747
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
780
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
748
781
 
749
782
  if (field_contains_hasbit(layout, field)) {
750
783
  slot_clear_hasbit(layout, storage, field);
@@ -837,7 +870,7 @@ VALUE layout_get(MessageLayout* layout,
837
870
  const void* storage,
838
871
  const upb_fielddef* field) {
839
872
  void* memory = slot_memory(layout, storage, field);
840
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
873
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
841
874
  bool field_set;
842
875
  if (field_contains_hasbit(layout, field)) {
843
876
  field_set = slot_is_hasbit_set(layout, storage, field);
@@ -910,7 +943,7 @@ void layout_set(MessageLayout* layout,
910
943
  const upb_fielddef* field,
911
944
  VALUE val) {
912
945
  void* memory = slot_memory(layout, storage, field);
913
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
946
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
914
947
 
915
948
  if (oneof) {
916
949
  uint32_t* oneof_case = slot_oneof_case(layout, storage, oneof);
@@ -953,7 +986,16 @@ void layout_set(MessageLayout* layout,
953
986
 
954
987
  if (layout->fields[upb_fielddef_index(field)].hasbit !=
955
988
  MESSAGE_FIELD_NO_HASBIT) {
956
- slot_set_hasbit(layout, storage, field);
989
+ if (val == Qnil) {
990
+ // No other field type has a hasbit and allows nil assignment.
991
+ if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
992
+ fprintf(stderr, "field: %s\n", upb_fielddef_fullname(field));
993
+ }
994
+ assert(upb_fielddef_type(field) == UPB_TYPE_MESSAGE);
995
+ slot_clear_hasbit(layout, storage, field);
996
+ } else {
997
+ slot_set_hasbit(layout, storage, field);
998
+ }
957
999
  }
958
1000
  }
959
1001
 
@@ -972,7 +1014,7 @@ void layout_init(MessageLayout* layout, void* storage) {
972
1014
 
973
1015
  void layout_mark(MessageLayout* layout, void* storage) {
974
1016
  VALUE* values = (VALUE*)CHARPTR_AT(storage, layout->value_offset);
975
- int noneofs = upb_msgdef_numoneofs(layout->msgdef);
1017
+ int noneofs = upb_msgdef_numrealoneofs(layout->msgdef);
976
1018
  int i;
977
1019
 
978
1020
  for (i = 0; i < layout->value_count; i++) {
@@ -994,7 +1036,7 @@ void layout_dup(MessageLayout* layout, void* to, void* from) {
994
1036
  !upb_msg_field_done(&it);
995
1037
  upb_msg_field_next(&it)) {
996
1038
  const upb_fielddef* field = upb_msg_iter_field(&it);
997
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
1039
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
998
1040
 
999
1041
  void* to_memory = slot_memory(layout, to, field);
1000
1042
  void* from_memory = slot_memory(layout, from, field);
@@ -1028,7 +1070,7 @@ void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
1028
1070
  !upb_msg_field_done(&it);
1029
1071
  upb_msg_field_next(&it)) {
1030
1072
  const upb_fielddef* field = upb_msg_iter_field(&it);
1031
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
1073
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
1032
1074
 
1033
1075
  void* to_memory = slot_memory(layout, to, field);
1034
1076
  void* from_memory = slot_memory(layout, from, field);
@@ -1068,7 +1110,7 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
1068
1110
  !upb_msg_field_done(&it);
1069
1111
  upb_msg_field_next(&it)) {
1070
1112
  const upb_fielddef* field = upb_msg_iter_field(&it);
1071
- const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
1113
+ const upb_oneofdef* oneof = upb_fielddef_realcontainingoneof(field);
1072
1114
 
1073
1115
  void* msg1_memory = slot_memory(layout, msg1, field);
1074
1116
  void* msg2_memory = slot_memory(layout, msg2, field);
@@ -1095,9 +1137,16 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
1095
1137
  return Qfalse;
1096
1138
  }
1097
1139
  } else {
1098
- if (slot_is_hasbit_set(layout, msg1, field) !=
1099
- slot_is_hasbit_set(layout, msg2, field) ||
1100
- !native_slot_eq(upb_fielddef_type(field),
1140
+ if (field_contains_hasbit(layout, field) &&
1141
+ slot_is_hasbit_set(layout, msg1, field) !=
1142
+ slot_is_hasbit_set(layout, msg2, field)) {
1143
+ // TODO(haberman): I don't think we should actually care about hasbits
1144
+ // here: an unset default should be able to equal a set default. But we
1145
+ // can address this later (will also have to make sure defaults are
1146
+ // being properly set when hasbit is clear).
1147
+ return Qfalse;
1148
+ }
1149
+ if (!native_slot_eq(upb_fielddef_type(field),
1101
1150
  field_type_class(layout, field), msg1_memory,
1102
1151
  msg2_memory)) {
1103
1152
  return Qfalse;