internal/filedesc: fix dependency on legacy generated enums

Suppose you have a generated message with an enum field that
has a default value, where the enum is declared in another proto file
that does not register its descriptors.
In such a situation, the enum dependency cannot be resolved and will
be left as a placeholder.

When unmarshalDefault is called, it will attempt to parse the enum
name stored as the default value, but panic since the placeholder enum
has no enum values known to it.

Instead of panicking, use a placeholder enum value that preserves the
name of default enum value and just use the enum number of 0.
This is not ideal, but is a better alternative than panicking.

Change-Id: I5ff6c351adbdd6fe7b41f2d4f215be4aa09e751f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/192500
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/filedesc/desc.go b/internal/filedesc/desc.go
index f18428f..86f24f0 100644
--- a/internal/filedesc/desc.go
+++ b/internal/filedesc/desc.go
@@ -524,11 +524,19 @@
 	if k == pref.EnumKind {
 		// If the enum is declared within the same file, be careful not to
 		// blindly call the Values method, lest we bind ourselves in a deadlock.
-		if ed, ok := ed.(*Enum); ok && ed.L0.ParentFile == pf {
-			evs = &ed.L2.Values
+		if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf {
+			evs = &e.L2.Values
 		} else {
 			evs = ed.Values()
 		}
+
+		// If we are unable to resolve the enum dependency, use a placeholder
+		// enum value since we will not be able to parse the default value.
+		if ed.IsPlaceholder() && pref.Name(b).IsValid() {
+			v := pref.ValueOf(pref.EnumNumber(0))
+			ev := PlaceholderEnumValue(ed.FullName().Parent().Append(pref.Name(b)))
+			return DefaultValue(v, ev)
+		}
 	}
 
 	v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)