make unions with type aliases more usable (#5019)

Some generic C++ and Rust code is not generated when unions use type
aliases because of potential ambiguity. Actually check for this
ambiguity and only disable offending code only if it is found.
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index c4f7c86..50ec760 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -1603,6 +1603,7 @@
   ECHECK(ParseMetaData(&enum_def->attributes));
   EXPECT('{');
   if (is_union) enum_def->vals.Add("NONE", new EnumVal("NONE", 0));
+  std::set<std::pair<BaseType, StructDef*>> union_types;
   for (;;) {
     if (opts.proto_mode && attribute_ == "option") {
       ECHECK(ParseProtoOption());
@@ -1633,10 +1634,17 @@
           if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
               ev.union_type.base_type != BASE_TYPE_STRING)
             return Error("union value type may only be table/struct/string");
-          enum_def->uses_type_aliases = true;
         } else {
           ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
         }
+        if (!enum_def->uses_multiple_type_instances) {
+          auto union_type_key = std::make_pair(ev.union_type.base_type, ev.union_type.struct_def);
+          if (union_types.count(union_type_key) > 0) {
+            enum_def->uses_multiple_type_instances = true;
+          } else {
+            union_types.insert(union_type_key);
+          }
+        }
       }
       if (Is('=')) {
         NEXT();