proto: never return nil []byte from Marshal when successful

It is a sufficiently common pattern to do something like the following:
	m.Proto2BytesField, ... = proto.Marshal(m2)

where the user is relying on Marshal to never return a nil byte slice,
otherwise it subtly changes the semantics of how the generated API
handles whether a proto2 "optional bytes" fields is populated or not.

Change-Id: Ie7508dbcdcc5f3295885609a91907c6eb4f04c1e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/228838
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/proto/encode.go b/proto/encode.go
index 862c38b..456bfda 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -80,6 +80,9 @@
 	}
 
 	out, err := MarshalOptions{}.marshal(nil, m.ProtoReflect())
+	if len(out.Buf) == 0 && err == nil {
+		out.Buf = emptyBytesForMessage(m)
+	}
 	return out.Buf, err
 }
 
@@ -91,9 +94,26 @@
 	}
 
 	out, err := o.marshal(nil, m.ProtoReflect())
+	if len(out.Buf) == 0 && err == nil {
+		out.Buf = emptyBytesForMessage(m)
+	}
 	return out.Buf, err
 }
 
+// emptyBytesForMessage returns a nil buffer if and only if m is invalid,
+// otherwise it returns a non-nil empty buffer.
+//
+// This is to assist the edge-case where user-code does the following:
+//	m1.OptionalBytes, _ = proto.Marshal(m2)
+// where they expect the proto2 "optional_bytes" field to be populated
+// if any only if m2 is a valid message.
+func emptyBytesForMessage(m Message) []byte {
+	if m == nil || !m.ProtoReflect().IsValid() {
+		return nil
+	}
+	return emptyBuf[:]
+}
+
 // MarshalAppend appends the wire-format encoding of m to b,
 // returning the result.
 func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
diff --git a/proto/encode_test.go b/proto/encode_test.go
index d8aabd9..1cdbabc 100644
--- a/proto/encode_test.go
+++ b/proto/encode_test.go
@@ -247,3 +247,28 @@
 		t.Errorf("after round-trip marshal, got len(m.OptionalBytes) = %v, want %v", got, want)
 	}
 }
+
+// TestEncodeEmpty tests for boundary conditions when producing an empty output.
+// These tests are not necessarily a statement of proper behavior,
+// but exist to detect accidental changes in behavior.
+func TestEncodeEmpty(t *testing.T) {
+	for _, m := range []proto.Message{nil, (*testpb.TestAllTypes)(nil), &testpb.TestAllTypes{}} {
+		isValid := m != nil && m.ProtoReflect().IsValid()
+
+		b, err := proto.Marshal(m)
+		if err != nil {
+			t.Errorf("proto.Marshal() = %v", err)
+		}
+		if isNil := b == nil; isNil == isValid {
+			t.Errorf("proto.Marshal() == nil: %v, want %v", isNil, !isValid)
+		}
+
+		b, err = proto.MarshalOptions{}.Marshal(m)
+		if err != nil {
+			t.Errorf("proto.MarshalOptions{}.Marshal() = %v", err)
+		}
+		if isNil := b == nil; isNil == isValid {
+			t.Errorf("proto.MarshalOptions{}.Marshal() = %v, want %v", isNil, !isValid)
+		}
+	}
+}