diff mbox

Go patch committed: Preliminary support for type aliases

Message ID CAOyqgcUDmVm7uqn1WQOtsYhF5Z3pM9Nhw57XbCRDZwPrdj+cQg@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Jan. 14, 2017, 1:50 a.m. UTC
This patch to the Go frontend adds preliminary support for type
aliases.  Type aliases are a feature proposed for Go 1.9, which will
come out in August.  I'm adding this to gccgo now so that the feature
is available in GCC 7 in case people start using it with Go 1.9.  It
is possible that the language feature will change or be withdrawn, so
this must be regarded as preliminary work.

Also, this does not include a planned change to the reflection
information.  Specifically, if an alias appears as an embedded field
in a struct, the reflection information will record the name of the
aliased type, not the name of the alias.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 244456)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-0ba4563a4b0dec4c01b90d7b3c9e2ce2cd58a96f
+ea73a80a6047f477d92fccc7de143a3ee1021c65
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/export.cc
===================================================================
--- gcc/go/gofrontend/export.cc	(revision 244166)
+++ gcc/go/gofrontend/export.cc	(working copy)
@@ -608,6 +608,9 @@  Export::write_type(const Type* type)
       // definition of the type may refer to the named type via a
       // pointer.
       this->type_refs_[type] = index;
+
+      if (named_type != NULL && named_type->is_alias())
+	this->write_c_string("= ");
     }
 
   type->export_type(this);
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 244330)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -108,12 +108,14 @@  Gogo::Gogo(Backend* backend, Linemap* li
   uint8_type->integer_type()->set_is_byte();
   Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type,
 						    loc);
+  byte_type->type_value()->set_is_alias();
   this->add_named_type(byte_type->type_value());
 
   // "rune" is an alias for "int32".
   int32_type->integer_type()->set_is_rune();
   Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type,
 						    loc);
+  rune_type->type_value()->set_is_alias();
   this->add_named_type(rune_type->type_value());
 
   this->add_named_type(Type::make_named_bool_type());
@@ -1775,6 +1777,10 @@  Gogo::start_function(const std::string&
 	  if (rtype->classification() == Type::TYPE_POINTER)
 	    rtype = rtype->points_to();
 
+	  while (rtype->named_type() != NULL
+		 && rtype->named_type()->is_alias())
+	    rtype = rtype->named_type()->real_type();
+
 	  if (rtype->is_error_type())
 	    ret = Named_object::make_function(name, NULL, function);
 	  else if (rtype->named_type() != NULL)
@@ -6865,7 +6871,7 @@  Type_declaration::add_method_declaration
   return ret;
 }
 
-// Return whether any methods ere defined.
+// Return whether any methods are defined.
 
 bool
 Type_declaration::has_methods() const
@@ -6878,6 +6884,36 @@  Type_declaration::has_methods() const
 void
 Type_declaration::define_methods(Named_type* nt)
 {
+  if (this->methods_.empty())
+    return;
+
+  while (nt->is_alias())
+    {
+      Type *t = nt->real_type()->forwarded();
+      if (t->named_type() != NULL)
+	nt = t->named_type();
+      else if (t->forward_declaration_type() != NULL)
+	{
+	  Named_object* no = t->forward_declaration_type()->named_object();
+	  Type_declaration* td = no->type_declaration_value();
+	  td->methods_.insert(td->methods_.end(), this->methods_.begin(),
+			      this->methods_.end());
+	  this->methods_.clear();
+	  return;
+	}
+      else
+	{
+	  for (std::vector<Named_object*>::const_iterator p =
+		 this->methods_.begin();
+	       p != this->methods_.end();
+	       ++p)
+	    go_error_at((*p)->location(),
+			("invalid receiver type "
+			 "(receiver must be a named type"));
+	  return;
+	}
+    }
+
   for (std::vector<Named_object*>::const_iterator p = this->methods_.begin();
        p != this->methods_.end();
        ++p)
Index: gcc/go/gofrontend/import.cc
===================================================================
--- gcc/go/gofrontend/import.cc	(revision 244166)
+++ gcc/go/gofrontend/import.cc	(working copy)
@@ -737,6 +737,13 @@  Import::read_type()
 
   this->require_c_string(" ");
 
+  bool is_alias = false;
+  if (this->match_c_string("= "))
+    {
+      stream->advance(2);
+      is_alias = true;
+    }
+
   // The package name may follow.  This is the name of the package in
   // the package clause of that package.  The type name will include
   // the pkgpath, which may be different.
@@ -810,6 +817,9 @@  Import::read_type()
 	  // This type has not yet been imported.
 	  ntype->clear_is_visible();
 
+	  if (is_alias)
+	    ntype->set_is_alias();
+
 	  if (!type->is_undefined() && type->interface_type() != NULL)
 	    this->gogo_->record_interface_type(type->interface_type());
 
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc	(revision 244166)
+++ gcc/go/gofrontend/parse.cc	(working copy)
@@ -1515,7 +1515,7 @@  Parse::type_decl()
   this->decl(&Parse::type_spec, NULL);
 }
 
-// TypeSpec = identifier Type .
+// TypeSpec = identifier ["="] Type .
 
 void
 Parse::type_spec(void*)
@@ -1531,6 +1531,13 @@  Parse::type_spec(void*)
   Location location = token->location();
   token = this->advance_token();
 
+  bool is_alias = false;
+  if (token->is_op(OPERATOR_EQ))
+    {
+      is_alias = true;
+      token = this->advance_token();
+    }
+
   // The scope of the type name starts at the point where the
   // identifier appears in the source code.  We implement this by
   // declaring the type before we read the type definition.
@@ -1542,13 +1549,13 @@  Parse::type_spec(void*)
     }
 
   Type* type;
-  if (name == "_" && this->peek_token()->is_keyword(KEYWORD_INTERFACE))
+  if (name == "_" && token->is_keyword(KEYWORD_INTERFACE))
     {
       // We call Parse::interface_type explicity here because we do not want
       // to record an interface with a blank type name.
       type = this->interface_type(false);
     }
-  else if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
+  else if (!token->is_op(OPERATOR_SEMICOLON))
     type = this->type();
   else
     {
@@ -1579,9 +1586,11 @@  Parse::type_spec(void*)
 	      type = Type::make_error_type();
 	    }
 
-	  this->gogo_->define_type(named_type,
-				   Type::make_named_type(named_type, type,
-							 location));
+	  Named_type* nt = Type::make_named_type(named_type, type, location);
+	  if (is_alias)
+	    nt->set_is_alias();
+
+	  this->gogo_->define_type(named_type, nt);
 	  go_assert(named_type->package() == NULL);
 	}
       else
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 244456)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -328,10 +328,10 @@  Type::are_identical(const Type* t1, cons
   t2 = t2->forwarded();
 
   // Ignore aliases for purposes of type identity.
-  if (t1->named_type() != NULL && t1->named_type()->is_alias())
-    t1 = t1->named_type()->real_type();
-  if (t2->named_type() != NULL && t2->named_type()->is_alias())
-    t2 = t2->named_type()->real_type();
+  while (t1->named_type() != NULL && t1->named_type()->is_alias())
+    t1 = t1->named_type()->real_type()->forwarded();
+  while (t2->named_type() != NULL && t2->named_type()->is_alias())
+    t2 = t2->named_type()->real_type()->forwarded();
 
   if (t1 == t2)
     return true;
@@ -822,6 +822,8 @@  Type::are_convertible(const Type* lhs, c
 unsigned int
 Type::hash_for_method(Gogo* gogo) const
 {
+  if (this->named_type() != NULL && this->named_type()->is_alias())
+    return this->named_type()->real_type()->hash_for_method(gogo);
   unsigned int ret = 0;
   if (this->classification_ != TYPE_FORWARD)
     ret += this->classification_;
@@ -1165,8 +1167,8 @@  Bexpression*
 Type::type_descriptor_pointer(Gogo* gogo, Location location)
 {
   Type* t = this->forwarded();
-  if (t->named_type() != NULL && t->named_type()->is_alias())
-    t = t->named_type()->real_type();
+  while (t->named_type() != NULL && t->named_type()->is_alias())
+    t = t->named_type()->real_type()->forwarded();
   if (t->type_descriptor_var_ == NULL)
     {
       t->make_type_descriptor_var(gogo);
@@ -1585,6 +1587,9 @@  Type::make_type_descriptor_ptr_type()
 bool
 Type::needs_specific_type_functions(Gogo* gogo)
 {
+  Named_type* nt = this->named_type();
+  if (nt != NULL && nt->is_alias())
+    return false;
   if (!this->is_comparable())
     return false;
   if (!this->compare_is_identity(gogo))
@@ -1593,7 +1598,6 @@  Type::needs_specific_type_functions(Gogo
   // We create a few predeclared types for type descriptors; they are
   // really just for the backend and don't need hash or equality
   // functions.
-  Named_type* nt = this->named_type();
   if (nt != NULL && Linemap::is_predeclared_location(nt->location()))
     return false;
 
@@ -1634,6 +1638,11 @@  Type::type_functions(Gogo* gogo, Named_t
 		     Function_type* equal_fntype, Named_object** hash_fn,
 		     Named_object** equal_fn)
 {
+  // If this loop leaves NAME as NULL, then the type does not have a
+  // name after all.
+  while (name != NULL && name->is_alias())
+    name = name->real_type()->named_type();
+
   if (!this->is_comparable())
     {
       *hash_fn = NULL;
@@ -2164,6 +2173,11 @@  Type::write_named_hash(Gogo* gogo, Named
   Location bloc = Linemap::predeclared_location();
 
   Named_type* base_type = name->real_type()->named_type();
+  while (base_type->is_alias())
+    {
+      base_type = base_type->real_type()->named_type();
+      go_assert(base_type != NULL);
+    }
   go_assert(base_type != NULL);
 
   // The pointer to the type we are going to hash.  This is an
@@ -2371,8 +2385,8 @@  Bexpression*
 Type::gc_symbol_pointer(Gogo* gogo)
 {
   Type* t = this->forwarded();
-  if (t->named_type() != NULL && t->named_type()->is_alias())
-    t = t->named_type()->real_type();
+  while (t->named_type() != NULL && t->named_type()->is_alias())
+    t = t->named_type()->real_type()->forwarded();
   if (t->gc_symbol_var_ == NULL)
     {
       t->make_gc_symbol_var(gogo);
@@ -4857,7 +4871,10 @@  Struct_field::field_name() const
       if (dt->forward_declaration_type() != NULL)
 	return dt->forward_declaration_type()->name();
       else if (dt->named_type() != NULL)
-	return dt->named_type()->name();
+	{
+	  // Note that this can be an alias name.
+	  return dt->named_type()->name();
+	}
       else if (t->is_error_type() || dt->is_error_type())
 	{
 	  static const std::string error_string = "*error*";
@@ -5786,7 +5803,12 @@  Struct_type::do_reflection(Gogo* gogo, s
       else
 	ret->append(Gogo::unpack_hidden_name(p->field_name()));
       ret->push_back(' ');
-      this->append_reflection(p->type(), gogo, ret);
+      if (p->is_anonymous()
+	  && p->type()->named_type() != NULL
+	  && p->type()->named_type()->is_alias())
+	p->type()->named_type()->append_reflection_type_name(gogo, true, ret);
+      else
+	this->append_reflection(p->type(), gogo, ret);
 
       if (p->has_tag())
 	{
@@ -5866,7 +5888,15 @@  Struct_type::do_mangled_name(Gogo* gogo,
 	      ret->append(buf);
 	      ret->append(n);
 	    }
-	  this->append_mangled_name(p->type(), gogo, ret);
+
+	  // For an anonymous field with an alias type, the field name
+	  // is the alias name.
+	  if (p->is_anonymous()
+	      && p->type()->named_type() != NULL
+	      && p->type()->named_type()->is_alias())
+	    p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
+	  else
+	    this->append_mangled_name(p->type(), gogo, ret);
 	  if (p->has_tag())
 	    {
 	      const std::string& tag(p->tag());
@@ -9313,18 +9343,6 @@  Named_type::message_name() const
   return this->named_object_->message_name();
 }
 
-// Whether this is an alias.  There are currently only two aliases so
-// we just recognize them by name.
-
-bool
-Named_type::is_alias() const
-{
-  if (!this->is_builtin())
-    return false;
-  const std::string& name(this->name());
-  return name == "byte" || name == "rune";
-}
-
 // Return the base type for this type.  We have to be careful about
 // circular type definitions, which are invalid but may be seen here.
 
@@ -9384,6 +9402,7 @@  Named_type::named_type_is_comparable(std
 Named_object*
 Named_type::add_method(const std::string& name, Function* function)
 {
+  go_assert(!this->is_alias_);
   if (this->local_methods_ == NULL)
     this->local_methods_ = new Bindings(NULL);
   return this->local_methods_->add_function(name, NULL, function);
@@ -9396,6 +9415,7 @@  Named_type::add_method_declaration(const
 				   Function_type* type,
 				   Location location)
 {
+  go_assert(!this->is_alias_);
   if (this->local_methods_ == NULL)
     this->local_methods_ = new Bindings(NULL);
   return this->local_methods_->add_function_declaration(name, package, type,
@@ -9407,6 +9427,7 @@  Named_type::add_method_declaration(const
 void
 Named_type::add_existing_method(Named_object* no)
 {
+  go_assert(!this->is_alias_);
   if (this->local_methods_ == NULL)
     this->local_methods_ = new Bindings(NULL);
   this->local_methods_->add_named_object(no);
@@ -9418,11 +9439,51 @@  Named_type::add_existing_method(Named_ob
 Named_object*
 Named_type::find_local_method(const std::string& name) const
 {
+  if (this->is_error_)
+    return NULL;
+  if (this->is_alias_)
+    {
+      Named_type* nt = this->type_->named_type();
+      if (nt != NULL)
+	{
+	  if (this->seen_alias_)
+	    return NULL;
+	  this->seen_alias_ = true;
+	  Named_object* ret = nt->find_local_method(name);
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      return NULL;
+    }
   if (this->local_methods_ == NULL)
     return NULL;
   return this->local_methods_->lookup(name);
 }
 
+// Return the list of local methods.
+
+const Bindings*
+Named_type::local_methods() const
+{
+  if (this->is_error_)
+    return NULL;
+  if (this->is_alias_)
+    {
+      Named_type* nt = this->type_->named_type();
+      if (nt != NULL)
+	{
+	  if (this->seen_alias_)
+	    return NULL;
+	  this->seen_alias_ = true;
+	  const Bindings* ret = nt->local_methods();
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      return NULL;
+    }
+  return this->local_methods_;
+}
+
 // Return whether NAME is an unexported field or method, for better
 // error reporting.
 
@@ -9430,6 +9491,22 @@  bool
 Named_type::is_unexported_local_method(Gogo* gogo,
 				       const std::string& name) const
 {
+  if (this->is_error_)
+    return false;
+  if (this->is_alias_)
+    {
+      Named_type* nt = this->type_->named_type();
+      if (nt != NULL)
+	{
+	  if (this->seen_alias_)
+	    return false;
+	  this->seen_alias_ = true;
+	  bool ret = nt->is_unexported_local_method(gogo, name);
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      return false;
+    }
   Bindings* methods = this->local_methods_;
   if (methods != NULL)
     {
@@ -9454,6 +9531,8 @@  Named_type::is_unexported_local_method(G
 void
 Named_type::finalize_methods(Gogo* gogo)
 {
+  if (this->is_alias_)
+    return;
   if (this->all_methods_ != NULL)
     return;
 
@@ -9474,6 +9553,56 @@  Named_type::finalize_methods(Gogo* gogo)
   Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
 }
 
+// Return whether this type has any methods.
+
+bool
+Named_type::has_any_methods() const
+{
+  if (this->is_error_)
+    return false;
+  if (this->is_alias_)
+    {
+      if (this->type_->named_type() != NULL)
+	{
+	  if (this->seen_alias_)
+	    return false;
+	  this->seen_alias_ = true;
+	  bool ret = this->type_->named_type()->has_any_methods();
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      if (this->type_->struct_type() != NULL)
+	return this->type_->struct_type()->has_any_methods();
+      return false;
+    }
+  return this->all_methods_ != NULL;
+}
+
+// Return the methods for this type.
+
+const Methods*
+Named_type::methods() const
+{
+  if (this->is_error_)
+    return NULL;
+  if (this->is_alias_)
+    {
+      if (this->type_->named_type() != NULL)
+	{
+	  if (this->seen_alias_)
+	    return NULL;
+	  this->seen_alias_ = true;
+	  const Methods* ret = this->type_->named_type()->methods();
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      if (this->type_->struct_type() != NULL)
+	return this->type_->struct_type()->methods();
+      return NULL;
+    }
+  return this->all_methods_;
+}
+
 // Return the method NAME, or NULL if there isn't one or if it is
 // ambiguous.  Set *IS_AMBIGUOUS if the method exists but is
 // ambiguous.
@@ -9481,6 +9610,26 @@  Named_type::finalize_methods(Gogo* gogo)
 Method*
 Named_type::method_function(const std::string& name, bool* is_ambiguous) const
 {
+  if (this->is_error_)
+    return NULL;
+  if (this->is_alias_)
+    {
+      if (is_ambiguous != NULL)
+	*is_ambiguous = false;
+      if (this->type_->named_type() != NULL)
+	{
+	  if (this->seen_alias_)
+	    return NULL;
+	  this->seen_alias_ = true;
+	  Named_type* nt = this->type_->named_type();
+	  Method* ret = nt->method_function(name, is_ambiguous);
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      if (this->type_->struct_type() != NULL)
+	return this->type_->struct_type()->method_function(name, is_ambiguous);
+      return NULL;
+    }
   return Type::method_function(this->all_methods_, name, is_ambiguous);
 }
 
@@ -9491,6 +9640,25 @@  Named_type::method_function(const std::s
 Expression*
 Named_type::interface_method_table(Interface_type* interface, bool is_pointer)
 {
+  if (this->is_error_)
+    return Expression::make_error(this->location_);
+  if (this->is_alias_)
+    {
+      if (this->type_->named_type() != NULL)
+	{
+	  if (this->seen_alias_)
+	    return Expression::make_error(this->location_);
+	  this->seen_alias_ = true;
+	  Named_type* nt = this->type_->named_type();
+	  Expression* ret = nt->interface_method_table(interface, is_pointer);
+	  this->seen_alias_ = false;
+	  return ret;
+	}
+      if (this->type_->struct_type() != NULL)
+	return this->type_->struct_type()->interface_method_table(interface,
+								  is_pointer);
+      go_unreachable();
+    }
   return Type::interface_method_table(this, interface, is_pointer,
                                       &this->interface_method_tables_,
                                       &this->pointer_interface_method_tables_);
@@ -9609,6 +9777,55 @@  Find_type_use::type(Type* type)
   return TRAVERSE_CONTINUE;
 }
 
+// Look for a circular reference of an alias.
+
+class Find_alias : public Traverse
+{
+ public:
+  Find_alias(Named_type* find_type)
+    : Traverse(traverse_types),
+      find_type_(find_type), found_(false)
+  { }
+
+  // Whether we found the type.
+  bool
+  found() const
+  { return this->found_; }
+
+ protected:
+  int
+  type(Type*);
+
+ private:
+  // The type we are looking for.
+  Named_type* find_type_;
+  // Whether we found the type.
+  bool found_;
+};
+
+int
+Find_alias::type(Type* type)
+{
+  Named_type* nt = type->named_type();
+  if (nt != NULL)
+    {
+      if (nt == this->find_type_)
+	{
+	  this->found_ = true;
+	  return TRAVERSE_EXIT;
+	}
+
+      // We started from `type T1 = T2`, where T1 is find_type_ and T2
+      // is, perhaps indirectly, the parameter TYPE.  If TYPE is not
+      // an alias itself, it's OK if whatever T2 is defined as refers
+      // to T1.
+      if (!nt->is_alias())
+	return TRAVERSE_SKIP_COMPONENTS;
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
 // Verify that a named type does not refer to itself.
 
 bool
@@ -9618,6 +9835,22 @@  Named_type::do_verify()
     return true;
   this->is_verified_ = true;
 
+  if (this->is_error_)
+    return false;
+
+  if (this->is_alias_)
+    {
+      Find_alias find(this);
+      Type::traverse(this->type_, &find);
+      if (find.found())
+	{
+	  go_error_at(this->location_, "invalid recursive alias %qs",
+		      this->message_name().c_str());
+	  this->is_error_ = true;
+	  return false;
+	}
+    }
+
   Find_type_use find(this);
   Type::traverse(this->type_, &find);
   if (find.found())
@@ -9718,8 +9951,11 @@  Named_type::do_needs_key_update()
 unsigned int
 Named_type::do_hash_for_method(Gogo* gogo) const
 {
-  if (this->is_alias())
-    return this->type_->named_type()->do_hash_for_method(gogo);
+  if (this->is_error_)
+    return 0;
+
+  // Aliases are handled in Type::hash_for_method.
+  go_assert(!this->is_alias_);
 
   const std::string& name(this->named_object()->name());
   unsigned int ret = Type::hash_string(name, 0);
@@ -10089,8 +10325,17 @@  Named_type::do_get_backend(Gogo* gogo)
 Expression*
 Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
 {
-  if (name == NULL && this->is_alias())
-    return this->type_->type_descriptor(gogo, this->type_);
+  if (this->is_error_)
+    return Expression::make_error(this->location_);
+  if (name == NULL && this->is_alias_)
+    {
+      if (this->seen_alias_)
+	return Expression::make_error(this->location_);
+      this->seen_alias_ = true;
+      Expression* ret = this->type_->type_descriptor(gogo, NULL);
+      this->seen_alias_ = false;
+      return ret;
+    }
 
   // If NAME is not NULL, then we don't really want the type
   // descriptor for this type; we want the descriptor for the
@@ -10106,9 +10351,25 @@  Named_type::do_type_descriptor(Gogo* gog
 void
 Named_type::do_reflection(Gogo* gogo, std::string* ret) const
 {
-  if (this->is_alias())
+  this->append_reflection_type_name(gogo, false, ret);
+}
+
+// Add to the reflection string.  For an alias we normally use the
+// real name, but if USE_ALIAS is true we use the alias name itself.
+
+void
+Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias,
+					std::string* ret) const
+{
+  if (this->is_error_)
+    return;
+  if (this->is_alias_ && !use_alias)
     {
+      if (this->seen_alias_)
+	return;
+      this->seen_alias_ = true;
       this->append_reflection(this->type_, gogo, ret);
+      this->seen_alias_ = false;
       return;
     }
   if (!this->is_builtin())
@@ -10173,9 +10434,25 @@  Named_type::do_gc_symbol(Gogo* gogo, Exp
 void
 Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
 {
-  if (this->is_alias())
+  this->append_mangled_type_name(gogo, false, ret);
+}
+
+// Get the mangled name.  For an alias we normally get the real name,
+// but if USE_ALIAS is true we use the alias name itself.
+
+void
+Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
+				     std::string* ret) const
+{
+  if (this->is_error_)
+    return;
+  if (this->is_alias_ && !use_alias)
     {
+      if (this->seen_alias_)
+	return;
+      this->seen_alias_ = true;
       this->append_mangled_name(this->type_, gogo, ret);
+      this->seen_alias_ = false;
       return;
     }
   Named_object* no = this->named_object_;
@@ -11392,7 +11669,7 @@  Forward_declaration_type::do_type_descri
       if (name != NULL)
 	return this->named_type_descriptor(gogo, t, name);
       else
-	return Expression::make_type_descriptor(t, ploc);
+	return Expression::make_error(this->named_object_->location());
     }
 }
 
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 244256)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -3061,10 +3061,10 @@  class Named_type : public Type
       type_(type), local_methods_(NULL), all_methods_(NULL),
       interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
       location_(location), named_btype_(NULL), dependencies_(),
-      is_visible_(true), is_error_(false), is_placeholder_(false),
-      is_converted_(false), is_circular_(false), is_verified_(false),
-      seen_(false), seen_in_compare_is_identity_(false),
-      seen_in_get_backend_(false)
+      is_alias_(false), is_visible_(true), is_error_(false),
+      is_placeholder_(false), is_converted_(false), is_circular_(false),
+      is_verified_(false), seen_(false), seen_in_compare_is_identity_(false),
+      seen_in_get_backend_(false), seen_alias_(false)
   { }
 
   // Return the associated Named_object.  This holds the actual name.
@@ -3082,6 +3082,17 @@  class Named_type : public Type
   set_named_object(Named_object* no)
   { this->named_object_ = no; }
 
+  // Whether this is an alias (type T1 = T2) rather than an ordinary
+  // named type (type T1 T2).
+  bool
+  is_alias() const
+  { return this->is_alias_; }
+
+  // Record that this type is an alias.
+  void
+  set_is_alias()
+  { this->is_alias_ = true; }
+
   // Return the function in which this type is defined.  This will
   // return NULL for a type defined in global scope.
   const Named_object*
@@ -3143,11 +3154,6 @@  class Named_type : public Type
   is_builtin() const
   { return Linemap::is_predeclared_location(this->location_); }
 
-  // Whether this is an alias.  There are currently two aliases: byte
-  // and rune.
-  bool
-  is_alias() const;
-
   // Whether this named type is valid.  A recursive named type is invalid.
   bool
   is_valid() const
@@ -3195,8 +3201,7 @@  class Named_type : public Type
 
   // Return the list of local methods.
   const Bindings*
-  local_methods() const
-  { return this->local_methods_; }
+  local_methods() const;
 
   // Build the complete list of methods, including those from
   // anonymous fields, and build method stubs if needed.
@@ -3206,14 +3211,12 @@  class Named_type : public Type
   // Return whether this type has any methods.  This should only be
   // called after the finalize_methods pass.
   bool
-  has_any_methods() const
-  { return this->all_methods_ != NULL; }
+  has_any_methods() const;
 
   // Return the methods for this type.  This should only be called
   // after the finalized_methods pass.
   const Methods*
-  methods() const
-  { return this->all_methods_; }
+  methods() const;
 
   // Return the method to use for NAME.  This returns NULL if there is
   // no such method or if the method is ambiguous.  When it returns
@@ -3246,6 +3249,16 @@  class Named_type : public Type
   is_named_backend_type_size_known() const
   { return this->named_btype_ != NULL && !this->is_placeholder_; }
 
+  // Add to the reflection string as for Type::append_reflection, but
+  // if USE_ALIAS use the alias name rather than the alias target.
+  void
+  append_reflection_type_name(Gogo*, bool use_alias, std::string*) const;
+
+  // Append the mangled type name as for Type::append_mangled_name,
+  // but if USE_ALIAS use the alias name rather than the alias target.
+  void
+  append_mangled_type_name(Gogo*, bool use_alias, std::string*) const;
+
   // Export the type.
   void
   export_named_type(Export*, const std::string& name) const;
@@ -3340,6 +3353,8 @@  class Named_type : public Type
   // where we can't convert S2 to the backend representation unless we
   // have converted S1.
   std::vector<Named_type*> dependencies_;
+  // Whether this is an alias type.
+  bool is_alias_;
   // Whether this type is visible.  This is false if this type was
   // created because it was referenced by an imported object, but the
   // type itself was not exported.  This will always be true for types
@@ -3367,6 +3382,8 @@  class Named_type : public Type
   bool seen_in_compare_is_identity_;
   // Like seen_, but used only by do_get_backend.
   bool seen_in_get_backend_;
+  // Like seen_, but used when resolving aliases.
+  mutable bool seen_alias_;
 };
 
 // A forward declaration.  This handles a type which has been declared