Browse Source

Merge pull request #692 from jskeet/tag-0

Change ReadTag/PeekTag behaviour to return 0 at EOF
Jan Tattermusch 10 years ago
parent
commit
ad8a889d1e
28 changed files with 167 additions and 405 deletions
  1. 3 9
      csharp/src/AddressBook/Addressbook.cs
  2. 5 15
      csharp/src/Google.Protobuf.Conformance/Conformance.cs
  3. 1 2
      csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs
  4. 11 9
      csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
  5. 12 7
      csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
  6. 2 2
      csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
  7. 7 21
      csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
  8. 1 3
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
  9. 1 3
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
  10. 10 30
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
  11. 35 105
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
  12. 4 12
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
  13. 24 32
      csharp/src/Google.Protobuf/CodedInputStream.cs
  14. 1 5
      csharp/src/Google.Protobuf/Collections/MapField.cs
  15. 1 5
      csharp/src/Google.Protobuf/FieldCodec.cs
  16. 1 1
      csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
  17. 22 66
      csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
  18. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
  19. 2 6
      csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
  20. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  21. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
  22. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
  23. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
  24. 3 9
      csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
  25. 1 3
      csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
  26. 5 15
      csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
  27. 9 27
      csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
  28. 1 3
      src/google/protobuf/compiler/csharp/csharp_message.cc

+ 3 - 9
csharp/src/AddressBook/Addressbook.cs

@@ -186,10 +186,8 @@ namespace Google.Protobuf.Examples.AddressBook {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -334,10 +332,8 @@ namespace Google.Protobuf.Examples.AddressBook {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -442,10 +438,8 @@ namespace Google.Protobuf.Examples.AddressBook {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 5 - 15
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -318,10 +318,8 @@ namespace Conformance {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -556,10 +554,8 @@ namespace Conformance {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1830,10 +1826,8 @@ namespace Conformance {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2259,10 +2253,8 @@ namespace Conformance {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -2378,10 +2370,8 @@ namespace Conformance {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 2
csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs

@@ -38,8 +38,7 @@ namespace Google.Protobuf
     {
         public static void AssertNextTag(this CodedInputStream input, uint expectedTag)
         {
-            uint tag;
-            Assert.IsTrue(input.ReadTag(out tag));
+            uint tag = input.ReadTag();
             Assert.AreEqual(expectedTag, tag);
         }
 

+ 11 - 9
csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs

@@ -279,9 +279,7 @@ namespace Google.Protobuf
             ms.Position = 0;
 
             CodedInputStream input = new CodedInputStream(ms);
-            uint testtag;
-            Assert.IsTrue(input.ReadTag(out testtag));
-            Assert.AreEqual(tag, testtag);
+            Assert.AreEqual(tag, input.ReadTag());
 
             // TODO(jonskeet): Should this be ArgumentNullException instead?
             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
@@ -377,9 +375,7 @@ namespace Google.Protobuf
 
             CodedInputStream input = new CodedInputStream(ms);
 
-            uint actualTag;
-            Assert.IsTrue(input.ReadTag(out actualTag));
-            Assert.AreEqual(tag, actualTag);
+            Assert.AreEqual(tag, input.ReadTag());
             string text = input.ReadString();
             Assert.AreEqual('\ufffd', text[0]);
         }
@@ -430,15 +426,21 @@ namespace Google.Protobuf
                 ms.Position = 0;
                 CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2]);
 
-                uint tag;
-                Assert.IsTrue(input.ReadTag(out tag));
+                uint tag = input.ReadTag();
                 Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));
                 Assert.AreEqual(100, input.ReadBytes().Length);
 
-                Assert.IsTrue(input.ReadTag(out tag));
+                tag = input.ReadTag();
                 Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag));
                 Assert.AreEqual(100, input.ReadBytes().Length);
             }
         }
+
+        [Test]
+        public void Tag0Throws()
+        {
+            var input = new CodedInputStream(new byte[] { 0 });
+            Assert.Throws<InvalidProtocolBufferException>(() => input.ReadTag());
+        }
     }
 }

+ 12 - 7
csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs

@@ -335,15 +335,16 @@ namespace Google.Protobuf
             // Now test Input stream:
             {
                 CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50]);
-                uint tag;
                 Assert.AreEqual(0, cin.Position);
                 // Field 1:
-                Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 1);
+                uint tag = cin.ReadTag();
+                Assert.AreEqual(1, tag >> 3);
                 Assert.AreEqual(1, cin.Position);
                 Assert.AreEqual(500, cin.ReadInt32());
                 Assert.AreEqual(3, cin.Position);
                 //Field 2:
-                Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 2);
+                tag = cin.ReadTag();
+                Assert.AreEqual(2, tag >> 3);
                 Assert.AreEqual(4, cin.Position);
                 int childlen = cin.ReadLength();
                 Assert.AreEqual(120, childlen);
@@ -353,19 +354,22 @@ namespace Google.Protobuf
                 // Now we are reading child message
                 {
                     // Field 11: numeric value: 500
-                    Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 11);
+                    tag = cin.ReadTag();
+                    Assert.AreEqual(11, tag >> 3);
                     Assert.AreEqual(6, cin.Position);
                     Assert.AreEqual(500, cin.ReadInt32());
                     Assert.AreEqual(8, cin.Position);
                     //Field 12: length delimited 120 bytes
-                    Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 12);
+                    tag = cin.ReadTag();
+                    Assert.AreEqual(12, tag >> 3);
                     Assert.AreEqual(9, cin.Position);
                     ByteString bstr = cin.ReadBytes();
                     Assert.AreEqual(110, bstr.Length);
                     Assert.AreEqual((byte) 109, bstr[109]);
                     Assert.AreEqual(120, cin.Position);
                     // Field 13: fixed numeric value: 501
-                    Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 13);
+                    tag = cin.ReadTag();
+                    Assert.AreEqual(13, tag >> 3);
                     // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit
                     Assert.AreEqual(121, cin.Position);
                     Assert.AreEqual(501, cin.ReadSFixed32());
@@ -375,7 +379,8 @@ namespace Google.Protobuf
                 cin.PopLimit(oldlimit);
                 Assert.AreEqual(125, cin.Position);
                 // Field 3: fixed numeric value: 501
-                Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 3);
+                tag = cin.ReadTag();
+                Assert.AreEqual(3, tag >> 3);
                 Assert.AreEqual(126, cin.Position);
                 Assert.AreEqual(501, cin.ReadSFixed32());
                 Assert.AreEqual(130, cin.Position);

+ 2 - 2
csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs

@@ -455,7 +455,7 @@ namespace Google.Protobuf.Collections
             Assert.AreEqual(0, output.SpaceLeft);
 
             CodedInputStream input = new CodedInputStream(bytes);
-            Assert.IsTrue(input.ReadTag(out tag));
+            tag = input.ReadTag();
 
             RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
             values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
@@ -493,7 +493,7 @@ namespace Google.Protobuf.Collections
             Assert.AreEqual(0, output.SpaceLeft);
 
             CodedInputStream input = new CodedInputStream(bytes);
-            Assert.IsTrue(input.ReadTag(out tag));
+            tag = input.ReadTag();
 
             RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
             values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));

+ 7 - 21
csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs

@@ -473,10 +473,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -647,10 +645,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -749,10 +745,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -862,10 +856,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1161,10 +1153,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1316,10 +1306,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1425,10 +1413,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs

@@ -136,10 +136,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs

@@ -122,10 +122,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 10 - 30
csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs

@@ -139,10 +139,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -221,10 +219,8 @@ namespace UnitTest.Issues.TestProtos {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -303,10 +299,8 @@ namespace UnitTest.Issues.TestProtos {
 
             public void MergeFrom(pb::CodedInputStream input) {
               uint tag;
-              while (input.ReadTag(out tag)) {
+              while ((tag = input.ReadTag()) != 0) {
                 switch(tag) {
-                  case 0:
-                    throw pb::InvalidProtocolBufferException.InvalidTag();
                   default:
                     if (pb::WireFormat.IsEndGroupTag(tag)) {
                       return;
@@ -444,10 +438,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -539,10 +531,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -737,10 +727,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -869,10 +857,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -998,10 +984,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1088,10 +1072,8 @@ namespace UnitTest.Issues.TestProtos {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -1358,10 +1340,8 @@ namespace UnitTest.Issues.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 35 - 105
csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs

@@ -1208,10 +1208,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1545,10 +1543,8 @@ namespace Google.Protobuf.TestProtos {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -1699,10 +1695,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1821,10 +1815,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1928,10 +1920,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2013,10 +2003,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2119,10 +2107,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2251,10 +2237,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2387,10 +2371,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2504,10 +2486,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2639,10 +2619,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2878,10 +2856,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3087,10 +3063,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3232,10 +3206,8 @@ namespace Google.Protobuf.TestProtos {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -3348,10 +3320,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3455,10 +3425,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3554,10 +3522,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3661,10 +3627,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3768,10 +3732,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3875,10 +3837,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3982,10 +3942,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4089,10 +4047,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4196,10 +4152,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4303,10 +4257,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4483,10 +4435,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4777,10 +4727,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5124,10 +5072,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5359,10 +5305,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5492,10 +5436,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5577,10 +5519,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5658,10 +5598,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5739,10 +5677,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5820,10 +5756,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5901,10 +5835,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -5982,10 +5914,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 4 - 12
csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs

@@ -676,10 +676,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1135,10 +1133,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1758,10 +1754,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2208,10 +2202,8 @@ namespace Google.Protobuf.TestProtos {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 24 - 32
csharp/src/Google.Protobuf/CodedInputStream.cs

@@ -254,37 +254,35 @@ namespace Google.Protobuf
         #region Reading of tags etc
 
         /// <summary>
-        /// Attempts to peek at the next field tag.
+        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
+        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
+        /// same value.)
         /// </summary>
-        public bool PeekNextTag(out uint fieldTag)
+        public uint PeekTag()
         {
             if (hasNextTag)
             {
-                fieldTag = nextTag;
-                return true;
+                return nextTag;
             }
 
             uint savedLast = lastTag;
-            hasNextTag = ReadTag(out nextTag);
-            lastTag = savedLast;
-            fieldTag = nextTag;
-            return hasNextTag;
+            nextTag = ReadTag();
+            hasNextTag = true;
+            lastTag = savedLast; // Undo the side effect of ReadTag
+            return nextTag;
         }
 
         /// <summary>
-        /// Attempts to read a field tag, returning false if we have reached the end
-        /// of the input data.
+        /// Reads a field tag, returning the tag of 0 for "end of stream".
         /// </summary>
-        /// <param name="fieldTag">The 'tag' of the field (id * 8 + wire-format)</param>
-        /// <returns>true if the next fieldTag was read</returns>
-        public bool ReadTag(out uint fieldTag)
+        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
+        public uint ReadTag()
         {
             if (hasNextTag)
             {
-                fieldTag = nextTag;
-                lastTag = fieldTag;
+                lastTag = nextTag;
                 hasNextTag = false;
-                return true;
+                return lastTag;
             }
 
             // Optimize for the incredibly common case of having at least two bytes left in the buffer,
@@ -294,7 +292,7 @@ namespace Google.Protobuf
                 int tmp = buffer[bufferPos++];
                 if (tmp < 128)
                 {
-                    fieldTag = (uint)tmp;
+                    lastTag = (uint)tmp;
                 }
                 else
                 {
@@ -302,13 +300,13 @@ namespace Google.Protobuf
                     if ((tmp = buffer[bufferPos++]) < 128)
                     {
                         result |= tmp << 7;
-                        fieldTag = (uint) result;
+                        lastTag = (uint) result;
                     }
                     else
                     {
                         // Nope, rewind and go the potentially slow route.
                         bufferPos -= 2;
-                        fieldTag = ReadRawVarint32();
+                        lastTag = ReadRawVarint32();
                     }
                 }
             }
@@ -316,20 +314,18 @@ namespace Google.Protobuf
             {
                 if (IsAtEnd)
                 {
-                    fieldTag = 0;
-                    lastTag = fieldTag;
-                    return false;
+                    lastTag = 0;
+                    return 0; // This is the only case in which we return 0.
                 }
 
-                fieldTag = ReadRawVarint32();
+                lastTag = ReadRawVarint32();
             }
-            lastTag = fieldTag;
             if (lastTag == 0)
             {
                 // If we actually read zero, that's not a valid tag.
                 throw InvalidProtocolBufferException.InvalidTag();
             }
-            return true;
+            return lastTag;
         }
 
         /// <summary>
@@ -580,14 +576,10 @@ namespace Google.Protobuf
         /// </summary>
         public bool MaybeConsumeTag(uint tag)
         {
-            uint next;
-            if (PeekNextTag(out next))
+            if (PeekTag() == tag)
             {
-                if (next == tag)
-                {
-                    hasNextTag = false;
-                    return true;
-                }
+                hasNextTag = false;
+                return true;
             }
             return false;
         }

+ 1 - 5
csharp/src/Google.Protobuf/Collections/MapField.cs

@@ -627,12 +627,8 @@ namespace Google.Protobuf.Collections
                 public void MergeFrom(CodedInputStream input)
                 {
                     uint tag;
-                    while (input.ReadTag(out tag))
+                    while ((tag = input.ReadTag()) != 0)
                     {
-                        if (tag == 0)
-                        {
-                            throw InvalidProtocolBufferException.InvalidTag();
-                        }
                         if (tag == codec.keyCodec.Tag)
                         {
                             Key = codec.keyCodec.Read(input);

+ 1 - 5
csharp/src/Google.Protobuf/FieldCodec.cs

@@ -298,12 +298,8 @@ namespace Google.Protobuf
 
                 uint tag;
                 T value = codec.DefaultValue;
-                while (input.ReadTag(out tag))
+                while ((tag = input.ReadTag()) != 0)
                 {
-                    if (tag == 0)
-                    {
-                        throw InvalidProtocolBufferException.InvalidTag();
-                    }
                     if (tag == codec.Tag)
                     {
                         value = codec.Read(input);

+ 1 - 1
csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs

@@ -70,7 +70,7 @@ namespace Google.Protobuf
         /// <summary>
         /// Creates an exception for an error condition of an invalid tag being encountered.
         /// </summary>
-        public static InvalidProtocolBufferException InvalidTag()
+        internal static InvalidProtocolBufferException InvalidTag()
         {
             return new InvalidProtocolBufferException(
                 "Protocol message contained an invalid tag (zero).");

+ 22 - 66
csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs

@@ -239,10 +239,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -538,10 +536,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -834,10 +830,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1003,10 +997,8 @@ namespace Google.Protobuf.Reflection {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -1136,10 +1128,8 @@ namespace Google.Protobuf.Reflection {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -1431,10 +1421,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1606,10 +1594,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1752,10 +1738,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1917,10 +1901,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2074,10 +2056,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2305,10 +2285,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2735,10 +2713,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -2990,10 +2966,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3237,10 +3211,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3422,10 +3394,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3551,10 +3521,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3676,10 +3644,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -3801,10 +3767,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4036,10 +4000,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4190,10 +4152,8 @@ namespace Google.Protobuf.Reflection {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;
@@ -4298,10 +4258,8 @@ namespace Google.Protobuf.Reflection {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -4470,10 +4428,8 @@ namespace Google.Protobuf.Reflection {
 
         public void MergeFrom(pb::CodedInputStream input) {
           uint tag;
-          while (input.ReadTag(out tag)) {
+          while ((tag = input.ReadTag()) != 0) {
             switch(tag) {
-              case 0:
-                throw pb::InvalidProtocolBufferException.InvalidTag();
               default:
                 if (pb::WireFormat.IsEndGroupTag(tag)) {
                   return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs

@@ -147,10 +147,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 2 - 6
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs

@@ -210,10 +210,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -438,10 +436,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs

@@ -148,10 +148,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs

@@ -103,10 +103,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs

@@ -117,10 +117,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs

@@ -126,10 +126,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 3 - 9
csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs

@@ -136,10 +136,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -391,10 +389,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -521,10 +517,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs

@@ -148,10 +148,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 5 - 15
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -223,10 +223,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -495,10 +493,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -717,10 +713,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -875,10 +869,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -1015,10 +1007,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 9 - 27
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs

@@ -135,10 +135,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -242,10 +240,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -349,10 +345,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -456,10 +450,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -563,10 +555,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -670,10 +660,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -777,10 +765,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -884,10 +870,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;
@@ -991,10 +975,8 @@ namespace Google.Protobuf.WellKnownTypes {
 
     public void MergeFrom(pb::CodedInputStream input) {
       uint tag;
-      while (input.ReadTag(out tag)) {
+      while ((tag = input.ReadTag()) != 0) {
         switch(tag) {
-          case 0:
-            throw pb::InvalidProtocolBufferException.InvalidTag();
           default:
             if (pb::WireFormat.IsEndGroupTag(tag)) {
               return;

+ 1 - 3
src/google/protobuf/compiler/csharp/csharp_message.cc

@@ -417,13 +417,11 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
   printer->Indent();
   printer->Print(
     "uint tag;\n"
-    "while (input.ReadTag(out tag)) {\n"
+    "while ((tag = input.ReadTag()) != 0) {\n"
     "  switch(tag) {\n");
   printer->Indent();
   printer->Indent();
   printer->Print(
-    "case 0:\n"  // 0 signals EOF / limit reached
-    "  throw pb::InvalidProtocolBufferException.InvalidTag();\n"
     "default:\n"
     "  if (pb::WireFormat.IsEndGroupTag(tag)) {\n"
     "    return;\n"