diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 1503672619f151a87a2a703278bc1dd8b6467985..a6b016ad710c530fbaa41009d5c05258cfe7c121 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-e1dc92a6037a3f81ea1b8ea8fb6207af33505f0c
+6db7e35d3bcd75ab3cb15296a5ddc5178038c9c1
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc
index 6365d6440b73d9cf59c16dfef416c2bf9c779c37..a64c7fd80a603577cb94f0fa48b863aaeb493af3 100644
--- a/gcc/go/gofrontend/export.cc
+++ b/gcc/go/gofrontend/export.cc
@@ -44,11 +44,49 @@ const int Export::checksum_len;
 // Constructor.
 
 Export::Export(Stream* stream)
-  : stream_(stream), type_refs_(), type_index_(1), packages_()
+  : stream_(stream), type_index_(1), packages_()
 {
   go_assert(Export::checksum_len == Go_sha1_helper::checksum_len);
 }
 
+// Type hash table operations, treating aliases as distinct.
+
+class Type_hash_alias_identical
+{
+ public:
+  unsigned int
+  operator()(const Type* type) const
+  {
+    return type->hash_for_method(NULL,
+				 (Type::COMPARE_ERRORS
+				  | Type::COMPARE_TAGS
+				  | Type::COMPARE_ALIASES));
+  }
+};
+
+class Type_alias_identical
+{
+ public:
+  bool
+  operator()(const Type* t1, const Type* t2) const
+  {
+    return Type::are_identical(t1, t2,
+			       (Type::COMPARE_ERRORS
+				| Type::COMPARE_TAGS
+				| Type::COMPARE_ALIASES),
+			       NULL);
+  }
+};
+
+// Mapping from Type objects to a constant index.  This would be nicer
+// as a field in Export, but then export.h would have to #include
+// types.h.
+
+typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical,
+			   Type_alias_identical) Type_refs;
+
+static Type_refs type_refs;
+
 // A functor to sort Named_object pointers by name.
 
 struct Sort_bindings
@@ -139,9 +177,10 @@ Export::export_globals(const std::string& package_name,
 
   std::sort(exports.begin(), exports.end(), Sort_bindings());
 
-  // Find all packages not explicitly imported but mentioned by types.
+  // Assign indexes to all exported types and types referenced by
+  // exported types, and collect all packages mentioned.
   Unordered_set(const Package*) type_imports;
-  this->prepare_types(&exports, &type_imports);
+  int unexported_type_index = this->prepare_types(&exports, &type_imports);
 
   // Although the export data is readable, at least this version is,
   // it is conceptually a binary format.  Start with a four byte
@@ -178,10 +217,17 @@ Export::export_globals(const std::string& package_name,
   // and ABI being used, although ideally any problems in that area
   // would be caught by the linker.
 
+  // Write out all the types, both exported and not.
+  this->write_types(unexported_type_index);
+
+  // Write out the non-type export data.
   for (std::vector<Named_object*>::const_iterator p = exports.begin();
        p != exports.end();
        ++p)
-    (*p)->export_named_object(this);
+    {
+      if (!(*p)->is_type())
+	(*p)->export_named_object(this);
+    }
 
   std::string checksum = this->stream_->checksum();
   std::string s = "checksum ";
@@ -204,9 +250,10 @@ Export::export_globals(const std::string& package_name,
 class Find_types_to_prepare : public Traverse
 {
  public:
-  Find_types_to_prepare(Unordered_set(const Package*)* imports)
+  Find_types_to_prepare(Export* exp,
+			Unordered_set(const Package*)* imports)
     : Traverse(traverse_types),
-      imports_(imports)
+      exp_(exp), imports_(imports)
   { }
 
   int
@@ -221,19 +268,34 @@ class Find_types_to_prepare : public Traverse
   traverse_named_type(Named_type*);
 
  private:
+  // Exporters.
+  Export* exp_;
   // List of packages we are building.
   Unordered_set(const Package*)* imports_;
 };
 
-// Traverse a type.
+// Set type index of referenced type, record package imports, and make
+// sure we traverse methods of named types.
 
 int
 Find_types_to_prepare::type(Type* type)
 {
-  // Skip forwarders.
+  // Skip forwarders; don't try to give them a type index.
   if (type->forward_declaration_type() != NULL)
     return TRAVERSE_CONTINUE;
 
+  // Skip the void type, which we'll see when exporting
+  // unsafe.Pointer.  The void type is not itself exported, because
+  // Pointer_type::do_export checks for it.
+  if (type->is_void_type())
+    return TRAVERSE_SKIP_COMPONENTS;
+
+  if (!this->exp_->set_type_index(type))
+    {
+      // We've already seen this type.
+      return TRAVERSE_SKIP_COMPONENTS;
+    }
+
   // At this stage of compilation traversing interface types traverses
   // the final list of methods, but we export the locally defined
   // methods.  If there is an embedded interface type we need to make
@@ -267,7 +329,7 @@ Find_types_to_prepare::type(Type* type)
 }
 
 // Traverse the types in a function type.  We don't need the function
-// type tself, just the receiver, parameter, and result types.
+// type itself, just the receiver, parameter, and result types.
 
 void
 Find_types_to_prepare::traverse_function(Function_type* type)
@@ -319,20 +381,34 @@ Find_types_to_prepare::traverse_named_type(Named_type* nt)
     }
 }
 
-// Collect all the pacakges we see in types, so that if we refer to
-// any types from indirectly importe packages we can tell the importer
-// about the package.
+// Prepare to export types by assigning a type index to every exported
+// type and every type referenced by an exported type.  Also collect
+// all the packages we see in types, so that if we refer to any types
+// from indirectly imported packages we can tell the importer about
+// the package.  This returns the number of exported types.
 
-void
+int
 Export::prepare_types(const std::vector<Named_object*>* exports,
 		      Unordered_set(const Package*)* imports)
 {
-  // Use a single index of the traversal class because traversal
+  // Assign indexes to all the exported types.
+  for (std::vector<Named_object*>::const_iterator p = exports->begin();
+       p != exports->end();
+       ++p)
+    {
+      if (!(*p)->is_type())
+	continue;
+      this->set_type_index((*p)->type_value());
+    }
+
+  int ret = this->type_index_;
+
+  // Use a single instance of the traversal class because traversal
   // classes keep track of which types they've already seen.  That
   // lets us avoid type reference loops.
-  Find_types_to_prepare find(imports);
+  Find_types_to_prepare find(this, imports);
 
-  // Traverse all the exported objects.
+  // Traverse all the exported objects and assign indexes to all types.
   for (std::vector<Named_object*>::const_iterator p = exports->begin();
        p != exports->end();
        ++p)
@@ -349,7 +425,8 @@ Export::prepare_types(const std::vector<Named_object*>* exports,
 	  break;
 
 	case Named_object::NAMED_OBJECT_TYPE:
-	  Type::traverse(no->type_value(), &find);
+	  Type::traverse(no->type_value()->real_type(), &find);
+	  find.traverse_named_type(no->type_value());
 	  break;
 
 	case Named_object::NAMED_OBJECT_VAR:
@@ -370,6 +447,31 @@ Export::prepare_types(const std::vector<Named_object*>* exports,
 	  break;
 	}
     }
+
+  return ret;
+}
+
+// Give a type an index if it doesn't already have one.  Return true
+// if we set the type index, false if it was already known.
+
+bool
+Export::set_type_index(Type* type)
+{
+  type = type->forwarded();
+
+  std::pair<Type_refs::iterator, bool> ins =
+    type_refs.insert(std::make_pair(type, 0));
+  if (!ins.second)
+    {
+      // We've already seen this type.
+      return false;
+    }
+
+  int index = this->type_index_;
+  ++this->type_index_;
+  ins.first->second = index;
+
+  return true;
 }
 
 // Sort packages.
@@ -705,6 +807,104 @@ Export::write_imported_init_fns(const std::string& package_name,
   this->write_c_string("\n");
 }
 
+// Write the types to the export stream.
+
+void
+Export::write_types(int unexported_type_index)
+{
+  // Map from type index to type.
+  std::vector<const Type*> types(static_cast<size_t>(this->type_index_));
+  for (Type_refs::const_iterator p = type_refs.begin();
+       p != type_refs.end();
+       ++p)
+    {
+      if (p->second >= 0)
+	types.at(p->second) = p->first;
+    }
+
+  // Write the type information to a buffer.
+  Stream_to_string type_data;
+  Export::Stream* orig_stream = this->stream_;
+  this->stream_ = &type_data;
+
+  std::vector<size_t> type_sizes(static_cast<size_t>(this->type_index_));
+  type_sizes[0] = 0;
+
+  // Start at 1 because type index 0 is not used.
+  size_t start_size = 0;
+  for (int i = 1; i < this->type_index_; ++i)
+    {
+      this->write_type_definition(types[i], i);
+
+      size_t cur_size = type_data.string().size();
+      type_sizes[i] = cur_size - start_size;
+      start_size = cur_size;
+    }
+
+  // Back to original stream.
+  this->stream_ = orig_stream;
+
+  // The line "types MAXP1 EXPORTEDP1 SIZES..." appears before the
+  // types.  MAXP1 is one more than the maximum type index used; that
+  // is, it is the size of the array we need to allocate to hold all
+  // the values.  Indexes 1 up to but not including EXPORTEDP1 are the
+  // exported types.  The other types are not exported.  SIZES... is a
+  // list of MAXP1-1 entries listing the size of the type definition
+  // for each type, starting at index 1.
+  char buf[100];
+  snprintf(buf, sizeof buf, "types %d %d", this->type_index_,
+	   unexported_type_index);
+  this->write_c_string(buf);
+
+  // Start at 1 because type index 0 is not used.
+  for (int i = 1; i < this->type_index_; ++i)
+    {
+      snprintf(buf, sizeof buf, " %lu",
+	       static_cast<unsigned long>(type_sizes[i]));
+      this->write_c_string(buf);
+    }
+  this->write_c_string("\n");
+  this->write_string(type_data.string());
+}
+
+// Write a single type to the export stream.
+
+void
+Export::write_type_definition(const Type* type, int index)
+{
+  this->write_c_string("type ");
+
+  char buf[30];
+  snprintf(buf, sizeof buf, "%d ", index);
+  this->write_c_string(buf);
+
+  const Named_type* nt = type->named_type();
+  if (nt != NULL)
+    {
+      const Named_object* no = nt->named_object();
+      const Package* package = no->package();
+
+      this->write_c_string("\"");
+      if (package != NULL && !Gogo::is_hidden_name(no->name()))
+	{
+	  this->write_string(package->pkgpath());
+	  this->write_c_string(".");
+	}
+      this->write_string(nt->named_object()->name());
+      this->write_c_string("\" ");
+
+      if (nt->is_alias())
+	this->write_c_string("= ");
+    }
+
+  type->export_type(this);
+
+  // Type::export_type will print a newline for a named type, but not
+  // otherwise.
+  if (nt == NULL)
+    this->write_c_string("\n");
+}
+
 // Write a name to the export stream.
 
 void
@@ -736,91 +936,19 @@ Export::write_unsigned(unsigned value)
   this->write_c_string(buf);
 }
 
-// Export a type.  We have to ensure that on import we create a single
-// Named_type node for each named type.  We do this by keeping a hash
-// table mapping named types to reference numbers.  The first time we
-// see a named type we assign it a reference number by making an entry
-// in the hash table.  If we see it again, we just refer to the
-// reference number.
-
-// Named types are, of course, associated with packages.  Note that we
-// may see a named type when importing one package, and then later see
-// the same named type when importing a different package.  The home
-// package may or may not be imported during this compilation.  The
-// reference number scheme has to get this all right.  Basic approach
-// taken from "On the Linearization of Graphs and Writing Symbol
-// Files" by Robert Griesemer.
+// Export a type.
 
 void
 Export::write_type(const Type* type)
 {
-  // We don't want to assign a reference number to a forward
-  // declaration to a type which was defined later.
   type = type->forwarded();
-
-  Type_refs::const_iterator p = this->type_refs_.find(type);
-  if (p != this->type_refs_.end())
-    {
-      // This type was already in the table.
-      int index = p->second;
-      go_assert(index != 0);
-      char buf[30];
-      snprintf(buf, sizeof buf, "<type %d>", index);
-      this->write_c_string(buf);
-      return;
-    }
-
-  const Named_type* named_type = type->named_type();
-  const Forward_declaration_type* forward = type->forward_declaration_type();
-
-  int index = this->type_index_;
-  ++this->type_index_;
-
+  Type_refs::const_iterator p = type_refs.find(type);
+  go_assert(p != type_refs.end());
+  int index = p->second;
+  go_assert(index != 0);
   char buf[30];
-  snprintf(buf, sizeof buf, "<type %d ", index);
+  snprintf(buf, sizeof buf, "<type %d>", index);
   this->write_c_string(buf);
-
-  if (named_type != NULL || forward != NULL)
-    {
-      const Named_object* named_object;
-      if (named_type != NULL)
-	{
-	  // The builtin types should have been predefined.
-	  go_assert(!Linemap::is_predeclared_location(named_type->location())
-		     || (named_type->named_object()->package()->package_name()
-			 == "unsafe"));
-	  named_object = named_type->named_object();
-	}
-      else
-	named_object = forward->named_object();
-
-      const Package* package = named_object->package();
-
-      std::string s = "\"";
-      if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
-	{
-	  s += package->pkgpath();
-	  s += '.';
-	}
-      s += named_object->name();
-      s += "\" ";
-      this->write_string(s);
-
-      // We must add a named type to the table now, since the
-      // 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);
-
-  this->write_c_string(">");
-
-  if (named_type == NULL)
-    this->type_refs_[type] = index;
 }
 
 // Export escape note.
@@ -873,18 +1001,15 @@ Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
   Named_object* named_object = gogo->lookup_global(name);
   go_assert(named_object != NULL && named_object->is_type());
   std::pair<Type_refs::iterator, bool> ins =
-    this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
+    type_refs.insert(std::make_pair(named_object->type_value(), code));
   go_assert(ins.second);
 
   // We also insert the underlying type.  We can see the underlying
-  // type at least for string and bool.  We skip the type aliases byte
-  // and rune here.
-  if (code != BUILTIN_BYTE && code != BUILTIN_RUNE)
-    {
-      Type* real_type = named_object->type_value()->real_type();
-      ins = this->type_refs_.insert(std::make_pair(real_type, code));
-      go_assert(ins.second);
-    }
+  // type at least for string and bool.  It's OK if this insert
+  // fails--we expect duplications here, and it doesn't matter when
+  // they occur.
+  Type* real_type = named_object->type_value()->real_type();
+  type_refs.insert(std::make_pair(real_type, code));
 }
 
 // Class Export::Stream.
diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h
index 55942818eec931994815b174dd41d3eab4628efb..84077a22c23b254832fcfe6fb510831c77f208a1 100644
--- a/gcc/go/gofrontend/export.h
+++ b/gcc/go/gofrontend/export.h
@@ -11,6 +11,7 @@
 
 class Go_sha1_helper;
 class Gogo;
+class Named_object;
 class Import_init;
 class Named_object;
 class Bindings;
@@ -154,6 +155,10 @@ class Export : public String_dump
 		 const Import_init_set& imported_init_fns,
 		 const Bindings* bindings);
 
+  // Set the index of a type.
+  bool
+  set_type_index(Type*);
+
   // Write a string to the export stream.
   void
   write_string(const std::string& s)
@@ -196,7 +201,7 @@ class Export : public String_dump
   Export& operator=(const Export&);
 
   // Prepare types for exporting.
-  void
+  int
   prepare_types(const std::vector<Named_object*>* exports,
 		Unordered_set(const Package*)* imports);
 
@@ -224,24 +229,27 @@ class Export : public String_dump
   write_imported_init_fns(const std::string& package_name,
 			  const std::string&, const Import_init_set&);
 
+  // Write out all types.
+  void
+  write_types(int unexported_type_index);
+
+  // Write out one type definition.
+  void
+  write_type_definition(const Type* type, int index);
+
   // Register one builtin type.
   void
   register_builtin_type(Gogo*, const char* name, Builtin_code);
 
-  // Mapping from Type objects to a constant index.
-  typedef Unordered_map(const Type*, int) Type_refs;
-
   // The stream to which we are writing data.
   Stream* stream_;
-  // Type mappings.
-  Type_refs type_refs_;
   // Index number of next type.
   int type_index_;
   // Packages we have written out.
   Unordered_set(const Package*) packages_;
 };
 
-// An export streamer which puts the export stream in a named section.
+// An export streamer that puts the export stream in a named section.
 
 class Stream_to_section : public Export::Stream
 {
@@ -256,4 +264,26 @@ class Stream_to_section : public Export::Stream
   Backend* backend_;
 };
 
+// An export streamer that puts the export stream in a string.
+
+class Stream_to_string : public Export::Stream
+{
+ public:
+  Stream_to_string()
+    : string_()
+  {}
+
+  const std::string&
+  string() const
+  { return this->string_; }
+
+ protected:
+  void
+  do_write(const char* s, size_t len)
+  { this->string_.append(s, len); }
+
+ private:
+  std::string string_;
+};
+
 #endif // !defined(GO_EXPORT_H)
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index bfbf682fc113ef35ccf87ebf599af9c000a9c4b2..2472245ebe95d35f96ada08e3ef9282a657b428d 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -7511,8 +7511,8 @@ Named_object::export_named_object(Export* exp) const
       break;
 
     case NAMED_OBJECT_TYPE:
-      this->type_value()->export_named_type(exp, this->name_);
-      break;
+      // Types are handled by export::write_types.
+      go_unreachable();
 
     case NAMED_OBJECT_TYPE_DECLARATION:
       go_error_at(this->type_declaration_value()->location(),
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 0864ee1d72a8d41fee3a851ba4e073bad8595b75..9c469ca32b5ece8a5a74fb20c8536c509a362096 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -12,9 +12,7 @@
 class Traverse;
 class Statement_inserter;
 class Type;
-class Type_hash_identical;
 class Type_equal;
-class Type_identical;
 class Typed_identifier;
 class Typed_identifier_list;
 class Function_type;
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index 8d17df708fc189a54017d9078b971c186ab4b24d..d30068f3b97e99fd495c70ad6464b470ab0bc71a 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -236,7 +236,7 @@ Import::find_export_data(const std::string& filename, int fd, Location location)
     }
 
   char buf[len];
-  ssize_t c = read(fd, buf, len);
+  ssize_t c = ::read(fd, buf, len);
   if (c < len)
     return NULL;
 
@@ -288,7 +288,7 @@ Import::find_object_export_data(const std::string& filename,
 
 Import::Import(Stream* stream, Location location)
   : gogo_(NULL), stream_(stream), location_(location), package_(NULL),
-    add_to_globals_(false),
+    add_to_globals_(false), type_data_(), type_pos_(0), type_offsets_(),
     builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
     types_(), version_(EXPORT_FORMAT_UNKNOWN)
 {
@@ -403,6 +403,12 @@ Import::import(Gogo* gogo, const std::string& local_name,
       if (stream->match_c_string("init"))
 	this->read_import_init_fns(gogo);
 
+      if (stream->match_c_string("types "))
+	{
+	  if (!this->read_types())
+	    return NULL;
+	}
+
       // Loop over all the input data for this package.
       while (!stream->saw_error())
 	{
@@ -585,6 +591,86 @@ Import::read_import_init_fns(Gogo* gogo)
     }
 }
 
+// Import the types.  Starting in export format version 3 all the
+// types are listed first.
+
+bool
+Import::read_types()
+{
+  this->require_c_string("types ");
+  std::string str = this->read_identifier();
+  int maxp1;
+  if (!this->string_to_int(str, false, &maxp1))
+    return false;
+
+  this->require_c_string(" ");
+  str = this->read_identifier();
+  int exportedp1;
+  if (!this->string_to_int(str, false, &exportedp1))
+    return false;
+
+  this->type_offsets_.resize(maxp1, std::make_pair<size_t, size_t>(0, 0));
+  size_t total_type_size = 0;
+  // Start at 1 because type index 0 not used.
+  for (int i = 1; i < maxp1; i++)
+    {
+      this->require_c_string(" ");
+      str = this->read_identifier();
+      int v;
+      if (!this->string_to_int(str, false, &v))
+	return false;
+      size_t vs = static_cast<size_t>(v);
+      this->type_offsets_[i] = std::make_pair(total_type_size, vs);
+      total_type_size += vs;
+    }
+
+  this->require_c_string("\n");
+
+  // Types can refer to each other in an unpredictable order.  Read
+  // all the type data into type_data_.  The type_offsets_ vector we
+  // just initialized provides indexes into type_data_.
+
+  this->type_pos_ = this->stream_->pos();
+  const char* type_data;
+  if (!this->stream_->peek(total_type_size, &type_data))
+    return false;
+  this->type_data_ = std::string(type_data, total_type_size);
+  this->advance(total_type_size);
+
+  this->types_.resize(maxp1, NULL);
+
+  // Parse all the exported types now, so that the names are properly
+  // bound and visible to the parser.  Parse unexported types lazily.
+
+  // Start at 1 because there is no type 0.
+  for (int i = 1; i < exportedp1; i++)
+    {
+      // We may have already parsed this type when we parsed an
+      // earlier type.
+      Type* type = this->types_[i];
+      if (type == NULL)
+	{
+	  if (!this->parse_type(i))
+	    return false;
+	  type = this->types_[i];
+	  go_assert(type != NULL);
+	}
+      Named_type* nt = type->named_type();
+      if (nt == NULL)
+	{
+	  go_error_at(this->location_,
+		      "error in import data: exported unnamed type %d",
+		      i);
+	  return false;
+	}
+      nt->set_is_visible();
+      if (this->add_to_globals_)
+	this->gogo_->add_named_type(nt);
+    }
+
+  return true;
+}
+
 // Import a constant.
 
 void
@@ -605,6 +691,18 @@ Import::import_const()
 void
 Import::import_type()
 {
+  if (this->version_ >= EXPORT_FORMAT_V3)
+    {
+      if (!this->stream_->saw_error())
+	{
+	  go_error_at(this->location_,
+		    "error in import data at %d: old type syntax",
+		    this->stream_->pos());
+	  this->stream_->set_saw_error();
+	}
+      return;
+    }
+
   Named_type* type;
   Named_type::import_named_type(this, &type);
 
@@ -694,9 +792,73 @@ Import::import_func(Package* package)
   return no;
 }
 
+// Read a type definition and initialize the entry in this->types_.
+// This parses the type definition saved by read_types earlier.  This
+// returns true on success, false on failure.
+
+bool
+Import::parse_type(int i)
+{
+  go_assert(i >= 0 && static_cast<size_t>(i) < this->types_.size());
+  go_assert(this->types_[i] == NULL);
+  size_t offset = this->type_offsets_[i].first;
+  size_t len = this->type_offsets_[i].second;
+
+  Stream* orig_stream = this->stream_;
+
+  Stream_from_string_ref stream(this->type_data_, offset, len);
+  stream.set_pos(this->type_pos_ + offset);
+  this->stream_ = &stream;
+
+  this->require_c_string("type ");
+  std::string str = this->read_identifier();
+  int id;
+  if (!this->string_to_int(str, false, &id))
+    {
+      this->stream_ = orig_stream;
+      return false;
+    }
+  if (i != id)
+    {
+      go_error_at(this->location_,
+		  ("error in import data at %d: "
+		   "type ID mismatch: got %d, want %d"),
+		  stream.pos(), id, i);
+      this->stream_ = orig_stream;
+      return false;
+    }
+
+  this->require_c_string(" ");
+  if (stream.peek_char() == '"')
+    {
+      stream.advance(1);
+      Type* type = this->read_named_type(i);
+      if (type->is_error_type())
+	{
+	  this->stream_ = orig_stream;
+	  return false;
+	}
+    }
+  else
+    {
+      Type* type = Type::import_type(this);
+      if (type->is_error_type())
+	{
+	  this->stream_ = orig_stream;
+	  return false;
+	}
+      this->types_[i] = type;
+
+      this->require_c_string("\n");
+    }
+
+  this->stream_ = orig_stream;
+  return true;
+}
+
 // Read a type in the import stream.  This records the type by the
-// type index.  If the type is named, it registers the name, but marks
-// it as invisible.
+// type index.  If the type is named (which can only happen with older
+// export formats), it registers the name, but marks it as invisible.
 
 Type*
 Import::read_type()
@@ -720,7 +882,28 @@ Import::read_type()
 
   if (c == '>')
     {
-      // This type was already defined.
+      // A reference to a type defined earlier.
+
+      if (index >= 0 && !this->type_data_.empty())
+	{
+	  if (static_cast<size_t>(index) >= this->type_offsets_.size())
+	    {
+	      go_error_at(this->location_,
+			  ("error in import data at %d: "
+			   "bad type index %d >= %d"),
+			  stream->pos(), index,
+			  static_cast<int>(this->type_offsets_.size()));
+	      stream->set_saw_error();
+	      return Type::make_error_type();
+	    }
+
+	  if (this->types_[index] == NULL)
+	    {
+	      if (!this->parse_type(index))
+		return Type::make_error_type();
+	    }
+	}
+
       if (index < 0
 	  ? (static_cast<size_t>(- index) >= this->builtin_types_.size()
 	     || this->builtin_types_[- index] == NULL)
@@ -737,11 +920,21 @@ Import::read_type()
       return index < 0 ? this->builtin_types_[- index] : this->types_[index];
     }
 
+  if (this->version_ >= EXPORT_FORMAT_V3)
+    {
+      if (!stream->saw_error())
+	go_error_at(this->location_,
+		    "error in import data at %d: expected %<>%>",
+		    stream->pos());
+      stream->set_saw_error();
+      return Type::make_error_type();
+    }
+
   if (c != ' ')
     {
       if (!stream->saw_error())
 	go_error_at(this->location_,
-		    "error in import data at %d: expect %< %> or %<>%>'",
+		    "error in import data at %d: expected %< %> or %<>%>'",
 		    stream->pos());
       stream->set_saw_error();
       stream->advance(1);
@@ -774,10 +967,25 @@ Import::read_type()
       return type;
     }
 
-  // This type has a name.
-
   stream->advance(1);
+
+  Type* type = this->read_named_type(index);
+
+  this->require_c_string(">");
+
+  return type;
+}
+
+// Read a named type from the import stream and store it in
+// this->types_[index].  The stream should be positioned immediately
+// after the '"' that starts the name.
+
+Type*
+Import::read_named_type(int index)
+{
+  Stream* stream = this->stream_;
   std::string type_name;
+  int c;
   while ((c = stream->get_char()) != '"')
     type_name += c;
 
@@ -863,7 +1071,7 @@ Import::read_type()
   // If there is no type definition, then this is just a forward
   // declaration of a type defined in some other file.
   Type* type;
-  if (this->match_c_string(">"))
+  if (this->match_c_string(">") || this->match_c_string("\n"))
     type = this->types_[index];
   else
     {
@@ -912,8 +1120,6 @@ Import::read_type()
 	}
     }
 
-  this->require_c_string(">");
-
   return type;
 }
 
@@ -1125,10 +1331,9 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
       *bytes = this->data_.data();
       return true;
     }
-  // Don't bother to handle the general case, since we don't need it.
-  go_assert(length < 64);
-  char buf[64];
-  ssize_t got = read(this->fd_, buf, length);
+
+  this->data_.resize(length);
+  ssize_t got = ::read(this->fd_, &this->data_[0], length);
 
   if (got < 0)
     {
@@ -1149,8 +1354,6 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
   if (static_cast<size_t>(got) < length)
     return false;
 
-  this->data_.assign(buf, got);
-
   *bytes = this->data_.data();
   return true;
 }
diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h
index dbdcc8fb4896c8e6e9e357b220c4c8ec42236ad9..cc7703bcc943871f7ec98586f999dc73309042f1 100644
--- a/gcc/go/gofrontend/import.h
+++ b/gcc/go/gofrontend/import.h
@@ -30,6 +30,11 @@ class Import
     Stream();
     virtual ~Stream();
 
+    // Set the position, for error messages.
+    void
+    set_pos(int pos)
+    { this->pos_ = pos; }
+
     // Return whether we have seen an error.
     bool
     saw_error() const
@@ -249,6 +254,10 @@ class Import
   void
   read_import_init_fns(Gogo*);
 
+  // Read the types.
+  bool
+  read_types();
+
   // Import a constant.
   void
   import_const();
@@ -265,6 +274,14 @@ class Import
   Named_object*
   import_func(Package*);
 
+  // Parse a type definition.
+  bool
+  parse_type(int index);
+
+  // Read a named type and store it at this->type_[index].
+  Type*
+  read_named_type(int index);
+
   // Register a single builtin type.
   void
   register_builtin_type(Gogo*, const char* name, Builtin_code);
@@ -299,6 +316,12 @@ class Import
   // Whether to add new objects to the global scope, rather than to a
   // package scope.
   bool add_to_globals_;
+  // All type data.
+  std::string type_data_;
+  // Position of type data in the stream.
+  int type_pos_;
+  // Mapping from type code to offset/length in type_data_.
+  std::vector<std::pair<size_t, size_t> > type_offsets_;
   // Mapping from negated builtin type codes to Type structures.
   std::vector<Named_type*> builtin_types_;
   // Mapping from exported type codes to Type structures.
@@ -399,4 +422,41 @@ class Stream_from_file : public Import::Stream
   std::string data_;
 };
 
+// Read import data from an offset into a std::string.  This uses a
+// reference to the string, to avoid copying, so the string must be
+// kept alive through some other mechanism.
+
+class Stream_from_string_ref : public Import::Stream
+{
+ public:
+  Stream_from_string_ref(const std::string& str, size_t offset, size_t length)
+    : str_(str), pos_(offset), end_(offset + length)
+  { }
+
+  ~Stream_from_string_ref()
+  {}
+
+ protected:
+  bool
+  do_peek(size_t length, const char** bytes)
+  {
+    if (this->pos_ + length > this->end_)
+      return false;
+    *bytes = &this->str_[this->pos_];
+    return true;
+  }
+
+  void
+  do_advance(size_t length)
+  { this->pos_ += length; }
+
+ private:
+  // A reference to the string we are reading from.
+  const std::string& str_;
+  // The current offset into the string.
+  size_t pos_;
+  // The index after the last byte we can read.
+  size_t end_;
+};
+
 #endif // !defined(GO_IMPORT_H)
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 94b332a25b2b9195e63949e66e00a8e6862782b3..2d348ba2c6f1539fdfa0dbdcf78ad6b350f7d5c3 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -10865,19 +10865,8 @@ Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias,
   ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
 }
 
-// Export the type.  This is called to export a global type.
-
-void
-Named_type::export_named_type(Export* exp, const std::string&) const
-{
-  // We don't need to write the name of the type here, because it will
-  // be written by Export::write_type anyhow.
-  exp->write_c_string("type ");
-  exp->write_type(this);
-  exp->write_c_string("\n");
-}
-
-// Import a named type.
+// Import a named type.  This is only used for export format versions
+// before version 3.
 
 void
 Named_type::import_named_type(Import* imp, Named_type** ptype)
@@ -10891,12 +10880,15 @@ Named_type::import_named_type(Import* imp, Named_type** ptype)
 }
 
 // Export the type when it is referenced by another type.  In this
-// case Export::export_type will already have issued the name.
+// case Export::export_type will already have issued the name.  The
+// output always ends with a newline, since that is convenient if
+// there are methods.
 
 void
 Named_type::do_export(Export* exp) const
 {
   exp->write_type(this->type_);
+  exp->write_c_string("\n");
 
   // To save space, we only export the methods directly attached to
   // this type.
@@ -10904,7 +10896,6 @@ Named_type::do_export(Export* exp) const
   if (methods == NULL)
     return;
 
-  exp->write_c_string("\n");
   for (Bindings::const_definitions_iterator p = methods->begin_definitions();
        p != methods->end_definitions();
        ++p)
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index c99b08a959d526d6dc587d0e49e28d741a2f6822..4898e67d7b809d533b4323e23998d42ef5398270 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -3445,10 +3445,6 @@ class Named_type : public Type
   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;
-
   // Import a named type.
   static void
   import_named_type(Import*, Named_type**);
diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go
index cd4e1d9288e041ef78ad40d28cf11d336245caa1..dc61e4cadc9e8349d6918603442fda7c3b99809a 100644
--- a/libgo/go/go/internal/gccgoimporter/parser.go
+++ b/libgo/go/go/internal/gccgoimporter/parser.go
@@ -18,7 +18,7 @@ import (
 )
 
 type parser struct {
-	scanner  scanner.Scanner
+	scanner  *scanner.Scanner
 	version  string                    // format version
 	tok      rune                      // current token
 	lit      string                    // literal string; only valid for Ident, Int, String tokens
@@ -27,18 +27,24 @@ type parser struct {
 	pkg      *types.Package            // reference to imported package
 	imports  map[string]*types.Package // package path -> package object
 	typeMap  map[int]types.Type        // type number -> type
+	typeData []string                  // unparsed type data
 	initdata InitData                  // package init priority data
 }
 
 func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
+	p.scanner = new(scanner.Scanner)
+	p.initScanner(filename, src)
+	p.imports = imports
+	p.typeMap = make(map[int]types.Type)
+}
+
+func (p *parser) initScanner(filename string, src io.Reader) {
 	p.scanner.Init(src)
 	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
 	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
 	p.scanner.Whitespace = 1<<'\t' | 1<<' '
 	p.scanner.Filename = filename // for good error messages
 	p.next()
-	p.imports = imports
-	p.typeMap = make(map[int]types.Type)
 }
 
 type importError struct {
@@ -720,6 +726,9 @@ func (p *parser) parseType(pkg *types.Package) (t types.Type) {
 		n := p.parseInt()
 
 		if p.tok == '>' {
+			if len(p.typeData) > 0 && p.typeMap[int(n)] == nil {
+				p.parseSavedType(pkg, int(n))
+			}
 			t = p.typeMap[int(n)]
 		} else {
 			t = p.parseTypeDefinition(pkg, int(n))
@@ -739,6 +748,67 @@ func (p *parser) parseType(pkg *types.Package) (t types.Type) {
 	return
 }
 
+// Types = "types" maxp1 exportedp1 (offset length)* .
+func (p *parser) parseTypes(pkg *types.Package) {
+	maxp1 := p.parseInt()
+	exportedp1 := p.parseInt()
+
+	type typeOffset struct {
+		offset int
+		length int
+	}
+	var typeOffsets []typeOffset
+
+	total := 0
+	for i := 1; i < int(maxp1); i++ {
+		len := int(p.parseInt())
+		typeOffsets = append(typeOffsets, typeOffset{total, len})
+		total += len
+	}
+
+	// We should now have p.tok pointing to the final newline.
+	// The next runes from the scanner should be the type data.
+
+	var sb strings.Builder
+	for sb.Len() < total {
+		r := p.scanner.Next()
+		if r == scanner.EOF {
+			p.error("unexpected EOF")
+		}
+		sb.WriteRune(r)
+	}
+	allTypeData := sb.String()
+
+	p.typeData = []string{""} // type 0, unused
+	for _, to := range typeOffsets {
+		p.typeData = append(p.typeData, allTypeData[to.offset:to.offset+to.length])
+	}
+
+	for i := 1; i < int(exportedp1); i++ {
+		p.parseSavedType(pkg, i)
+	}
+}
+
+// parseSavedType parses one saved type definition.
+func (p *parser) parseSavedType(pkg *types.Package, i int) {
+	defer func(s *scanner.Scanner, tok rune, lit string) {
+		p.scanner = s
+		p.tok = tok
+		p.lit = lit
+	}(p.scanner, p.tok, p.lit)
+
+	p.scanner = new(scanner.Scanner)
+	p.initScanner(p.scanner.Filename, strings.NewReader(p.typeData[i]))
+	p.expectKeyword("type")
+	id := int(p.parseInt())
+	if id != i {
+		p.errorf("type ID mismatch: got %d, want %d", id, i)
+	}
+	if p.typeMap[i] == nil {
+		p.typeMap[i] = p.parseTypeDefinition(pkg, i)
+	}
+}
+
 // PackageInit = unquotedString unquotedString int .
 func (p *parser) parsePackageInit() PackageInit {
 	name := p.parseUnquotedString()
@@ -883,6 +953,11 @@ func (p *parser) parseDirective() {
 		p.getPkg(pkgpath, pkgname)
 		p.expectEOL()
 
+	case "types":
+		p.next()
+		p.parseTypes(p.pkg)
+		p.expectEOL()
+
 	case "func":
 		p.next()
 		fun := p.parseFunc(p.pkg)