This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Add -fgo-pkgpath option


This patch to the Go frontend adds a new command line option:
-fgo-pkgpath.  This permits setting the string that is returned by the
PkgPath() method of reflect.Type for types defined in the package being
compiled.  It also sets the prefix used for symbol names.  This largely
replaces the existing -fgo-prefix option, although I retained
-fgo-prefix for backward compatibility.  This will permit libgo to have
PkgPath values that are the same as the ones returned by the other Go
compiler.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline and 4.7 branch.

Ian


2012-05-09  Ian Lance Taylor  <iant@google.com>

	* lang.opt: Add -fgo-pkgpath.
	* go-lang.c (go_pkgpath): New static variable.
	(go_prefix): New static variable.
	(go_langhook_init): Pass go_pkgpath and go_prefix to
	go_create_gogo.
	(go_langhook_handle_option): Handle -fgo-pkgpath.  Change
	-fgo-prefix handling to just set go_prefix.
	* go-c.h (go_set_prefix): Don't declare.
	(go_create_gogo): Add pkgpath and prefix to declaration.
	* go-gcc.cc (Gcc_backend::global_variable): Change unique_prefix
	to pkgpath.  Don't include the package name in the asm name.
	* gccgo.texi (Invoking gccgo): Document -fgo-pkgpath.  Update the
	docs for -fgo-prefix.


Index: gcc/go/lang.opt
===================================================================
--- gcc/go/lang.opt	(revision 187020)
+++ gcc/go/lang.opt	(working copy)
@@ -53,6 +53,10 @@ fgo-optimize-
 Go Joined RejectNegative
 -fgo-optimize-<type>	Turn on optimization passes in the frontend
 
+fgo-pkgpath=
+Go Joined RejectNegative
+-fgo-pkgpath=<string>	Set Go package path
+
 fgo-prefix=
 Go Joined RejectNegative
 -fgo-prefix=<string>	Set package-specific prefix for exported Go names
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 187020)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -271,7 +271,7 @@ class Gcc_backend : public Backend
 
   Bvariable*
   global_variable(const std::string& package_name,
-		  const std::string& unique_prefix,
+		  const std::string& pkgpath,
 		  const std::string& name,
 		  Btype* btype,
 		  bool is_external,
@@ -1281,7 +1281,7 @@ Gcc_backend::non_zero_size_type(tree typ
 
 Bvariable*
 Gcc_backend::global_variable(const std::string& package_name,
-			     const std::string& unique_prefix,
+			     const std::string& pkgpath,
 			     const std::string& name,
 			     Btype* btype,
 			     bool is_external,
@@ -1310,9 +1310,9 @@ Gcc_backend::global_variable(const std::
     {
       TREE_PUBLIC(decl) = 1;
 
-      std::string asm_name(unique_prefix);
+      std::string asm_name(pkgpath);
       asm_name.push_back('.');
-      asm_name.append(var_name);
+      asm_name.append(name);
       SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
     }
   TREE_USED(decl) = 1;
Index: gcc/go/gccgo.texi
===================================================================
--- gcc/go/gccgo.texi	(revision 187020)
+++ gcc/go/gccgo.texi	(working copy)
@@ -157,14 +157,32 @@ compile time.
 When linking, specify a library search directory, as with
 @command{gcc}.
 
+@item -fgo-pkgpath=@var{string}
+@cindex @option{-fgo-pkgpath}
+Set the package path to use.  This sets the value returned by the
+PkgPath method of reflect.Type objects.  It is also used for the names
+of globally visible symbols.  The argument to this option should
+normally be the string that will be used to import this package after
+it has been installed; in other words, a pathname within the
+directories specified by the @option{-I} option.
+
 @item -fgo-prefix=@var{string}
 @cindex @option{-fgo-prefix}
+An alternative to @option{-fgo-pkgpath}.  The argument will be
+combined with the package name from the source file to produce the
+package path.  If @option{-fgo-pkgpath} is used, @option{-fgo-prefix}
+will be ignored.
+
 Go permits a single program to include more than one package with the
-same name.  This option is required to make this work with
-@command{gccgo}.  The argument to this option may be any string.  Each
-package with the same name must use a distinct @option{-fgo-prefix}
-option.  The argument is typically the full path under which the
-package will be installed, as that must obviously be unique.
+same name in the @code{package} clause in the source file, though
+obviously the two packages must be imported using different pathnames.
+In order for this to work with @command{gccgo}, either
+@option{-fgo-pkgpath} or @option{-fgo-prefix} must be specified when
+compiling a package.
+
+Using either @option{-fgo-pkgpath} or @option{-fgo-prefix} disables
+the special treatment of the @code{main} package and permits that
+package to be imported like any other.
 
 @item -frequire-return-statement
 @itemx -fno-require-return-statement
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 187142)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -36,8 +36,12 @@ Gogo::Gogo(Backend* backend, Linemap* li
     need_init_fn_(false),
     init_fn_name_(),
     imported_init_fns_(),
-    unique_prefix_(),
-    unique_prefix_specified_(false),
+    pkgpath_(),
+    pkgpath_symbol_(),
+    prefix_(),
+    pkgpath_set_(false),
+    pkgpath_from_option_(false),
+    prefix_from_option_(false),
     verify_types_(),
     interface_types_(),
     specific_type_functions_(),
@@ -233,6 +237,72 @@ Gogo::Gogo(Backend* backend, Linemap* li
   this->globals_->add_function_declaration("delete", NULL, delete_type, loc);
 }
 
+// Convert a pkgpath into a string suitable for a symbol.  Note that
+// this transformation is convenient but imperfect.  A -fgo-pkgpath
+// option of a/b_c will conflict with a -fgo-pkgpath option of a_b/c,
+// possibly leading to link time errors.
+
+std::string
+Gogo::pkgpath_for_symbol(const std::string& pkgpath)
+{
+  std::string s = pkgpath;
+  for (size_t i = 0; i < s.length(); ++i)
+    {
+      char c = s[i];
+      if ((c >= 'a' && c <= 'z')
+	  || (c >= 'A' && c <= 'Z')
+	  || (c >= '0' && c <= '9')
+	  || c == '_'
+	  || c == '.'
+	  || c == '$')
+	;
+      else
+	s[i] = '_';
+    }
+  return s;
+}
+
+// Get the package path to use for type reflection data.  This should
+// ideally be unique across the entire link.
+
+const std::string&
+Gogo::pkgpath() const
+{
+  go_assert(this->pkgpath_set_);
+  return this->pkgpath_;
+}
+
+// Set the package path from the -fgo-pkgpath command line option.
+
+void
+Gogo::set_pkgpath(const std::string& arg)
+{
+  go_assert(!this->pkgpath_set_);
+  this->pkgpath_ = arg;
+  this->pkgpath_set_ = true;
+  this->pkgpath_from_option_ = true;
+}
+
+// Get the package path to use for symbol names.
+
+const std::string&
+Gogo::pkgpath_symbol() const
+{
+  go_assert(this->pkgpath_set_);
+  return this->pkgpath_symbol_;
+}
+
+// Set the unique prefix to use to determine the package path, from
+// the -fgo-prefix command line option.
+
+void
+Gogo::set_prefix(const std::string& arg)
+{
+  go_assert(!this->prefix_from_option_);
+  this->prefix_ = arg;
+  this->prefix_from_option_ = true;
+}
+
 // Munge name for use in an error message.
 
 std::string
@@ -247,7 +317,7 @@ const std::string&
 Gogo::package_name() const
 {
   go_assert(this->package_ != NULL);
-  return this->package_->name();
+  return this->package_->package_name();
 }
 
 // Set the package name.
@@ -256,24 +326,29 @@ void
 Gogo::set_package_name(const std::string& package_name,
 		       Location location)
 {
-  if (this->package_ != NULL && this->package_->name() != package_name)
+  if (this->package_ != NULL)
     {
-      error_at(location, "expected package %<%s%>",
-	       Gogo::message_name(this->package_->name()).c_str());
+      if (this->package_->package_name() != package_name)
+	error_at(location, "expected package %<%s%>",
+		 Gogo::message_name(this->package_->package_name()).c_str());
       return;
     }
 
-  // If the user did not specify a unique prefix, we always use "go".
-  // This in effect requires that the package name be unique.
-  if (this->unique_prefix_.empty())
-    this->unique_prefix_ = "go";
-
-  this->package_ = this->register_package(package_name, this->unique_prefix_,
-					  location);
-
-  // We used to permit people to qualify symbols with the current
-  // package name (e.g., P.x), but we no longer do.
-  // this->globals_->add_package(package_name, this->package_);
+  // Now that we know the name of the package we are compiling, set
+  // the package path to use for reflect.Type.PkgPath and global
+  // symbol names.
+  if (!this->pkgpath_set_)
+    {
+      if (!this->prefix_from_option_)
+	this->prefix_ = "go";
+      this->pkgpath_ = this->prefix_ + '.' + package_name;
+      this->pkgpath_set_ = true;
+    }
+
+  this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_);
+
+  this->package_ = this->register_package(this->pkgpath_, location);
+  this->package_->set_package_name(package_name, location);
 
   if (this->is_main_package())
     {
@@ -287,12 +362,14 @@ Gogo::set_package_name(const std::string
 }
 
 // Return whether this is the "main" package.  This is not true if
-// -fgo-prefix was used.
+// -fgo-pkgpath or -fgo-prefix was used.
 
 bool
 Gogo::is_main_package() const
 {
-  return this->package_name() == "main" && !this->unique_prefix_specified_;
+  return (this->package_name() == "main"
+	  && !this->pkgpath_from_option_
+	  && !this->prefix_from_option_);
 }
 
 // Import a package.
@@ -319,7 +396,8 @@ Gogo::import_package(const std::string& 
       bool is_ln_exported = is_local_name_exported;
       if (ln.empty())
 	{
-	  ln = package->name();
+	  ln = package->package_name();
+	  go_assert(!ln.empty());
 	  is_ln_exported = Lex::is_exported_name(ln);
 	}
       if (ln == ".")
@@ -353,11 +431,10 @@ Gogo::import_package(const std::string& 
   Package* package = imp.import(this, local_name, is_local_name_exported);
   if (package != NULL)
     {
-      if (package->name() == this->package_name()
-	  && package->unique_prefix() == this->unique_prefix())
+      if (package->pkgpath() == this->pkgpath())
 	error_at(location,
-		 ("imported package uses same package name and prefix "
-		  "as package being compiled (see -fgo-prefix option)"));
+		 ("imported package uses same package path as package "
+		  "being compiled (see -fgo-pkgpath option)"));
 
       this->imports_.insert(std::make_pair(filename, package));
       package->set_is_imported();
@@ -510,38 +587,21 @@ Package*
 Gogo::add_imported_package(const std::string& real_name,
 			   const std::string& alias_arg,
 			   bool is_alias_exported,
-			   const std::string& unique_prefix,
+			   const std::string& pkgpath,
 			   Location location,
 			   bool* padd_to_globals)
 {
-  // FIXME: Now that we compile packages as a whole, should we permit
-  // importing the current package?
-  if (this->package_name() == real_name
-      && this->unique_prefix() == unique_prefix)
-    {
-      *padd_to_globals = false;
-      if (!alias_arg.empty() && alias_arg != ".")
-	{
-	  std::string alias = this->pack_hidden_name(alias_arg,
-						     is_alias_exported);
-	  this->package_->bindings()->add_package(alias, this->package_);
-	}
-      return this->package_;
-    }
-  else if (alias_arg == ".")
-    {
-      *padd_to_globals = true;
-      return this->register_package(real_name, unique_prefix, location);
-    }
+  Package* ret = this->register_package(pkgpath, location);
+  ret->set_package_name(real_name, location);
+
+  *padd_to_globals = false;
+
+  if (alias_arg == ".")
+    *padd_to_globals = true;
   else if (alias_arg == "_")
-    {
-      Package* ret = this->register_package(real_name, unique_prefix, location);
-      ret->set_uses_sink_alias();
-      return ret;
-    }
+    ret->set_uses_sink_alias();
   else
     {
-      *padd_to_globals = false;
       std::string alias = alias_arg;
       if (alias.empty())
 	{
@@ -549,57 +609,37 @@ Gogo::add_imported_package(const std::st
 	  is_alias_exported = Lex::is_exported_name(alias);
 	}
       alias = this->pack_hidden_name(alias, is_alias_exported);
-      Named_object* no = this->add_package(real_name, alias, unique_prefix,
-					   location);
+      Named_object* no = this->package_->bindings()->add_package(alias, ret);
       if (!no->is_package())
 	return NULL;
-      return no->package_value();
     }
-}
 
-// Add a package.
-
-Named_object*
-Gogo::add_package(const std::string& real_name, const std::string& alias,
-		  const std::string& unique_prefix, Location location)
-{
-  go_assert(this->in_global_scope());
-
-  // Register the package.  Note that we might have already seen it in
-  // an earlier import.
-  Package* package = this->register_package(real_name, unique_prefix, location);
-
-  return this->package_->bindings()->add_package(alias, package);
+  return ret;
 }
 
 // Register a package.  This package may or may not be imported.  This
 // returns the Package structure for the package, creating if it
-// necessary.
+// necessary.  LOCATION is the location of the import statement that
+// led us to see this package.
 
 Package*
-Gogo::register_package(const std::string& package_name,
-		       const std::string& unique_prefix,
-		       Location location)
+Gogo::register_package(const std::string& pkgpath, Location location)
 {
-  go_assert(!unique_prefix.empty() && !package_name.empty());
-  std::string name = unique_prefix + '.' + package_name;
   Package* package = NULL;
   std::pair<Packages::iterator, bool> ins =
-    this->packages_.insert(std::make_pair(name, package));
+    this->packages_.insert(std::make_pair(pkgpath, package));
   if (!ins.second)
     {
       // We have seen this package name before.
       package = ins.first->second;
-      go_assert(package != NULL);
-      go_assert(package->name() == package_name
-		 && package->unique_prefix() == unique_prefix);
+      go_assert(package != NULL && package->pkgpath() == pkgpath);
       if (Linemap::is_unknown_location(package->location()))
 	package->set_location(location);
     }
   else
     {
       // First time we have seen this package name.
-      package = new Package(package_name, unique_prefix, location);
+      package = new Package(pkgpath, location);
       go_assert(ins.first->second == NULL);
       ins.first->second = package;
     }
@@ -1151,7 +1191,7 @@ Gogo::clear_file_scope()
 	  && !package->uses_sink_alias()
 	  && !saw_errors())
 	error_at(package->location(), "imported and not used: %s",
-		 Gogo::message_name(package->name()).c_str());
+		 Gogo::message_name(package->package_name()).c_str());
       package->clear_is_imported();
       package->clear_uses_sink_alias();
       package->clear_used();
@@ -2822,27 +2862,6 @@ Gogo::check_return_statements()
   this->traverse(&traverse);
 }
 
-// Get the unique prefix to use before all exported symbols.  This
-// must be unique across the entire link.
-
-const std::string&
-Gogo::unique_prefix() const
-{
-  go_assert(!this->unique_prefix_.empty());
-  return this->unique_prefix_;
-}
-
-// Set the unique prefix to use before all exported symbols.  This
-// comes from the command line option -fgo-prefix=XXX.
-
-void
-Gogo::set_unique_prefix(const std::string& arg)
-{
-  go_assert(this->unique_prefix_.empty());
-  this->unique_prefix_ = arg;
-  this->unique_prefix_specified_ = true;
-}
-
 // Work out the package priority.  It is one more than the maximum
 // priority of an imported package.
 
@@ -2870,7 +2889,7 @@ Gogo::do_exports()
   Export exp(&stream);
   exp.register_builtin_types(this);
   exp.export_globals(this->package_name(),
-		     this->unique_prefix(),
+		     this->pkgpath(),
 		     this->package_priority(),
 		     this->imports_,
 		     (this->need_init_fn_ && !this->is_main_package()
@@ -4199,10 +4218,10 @@ Variable::get_backend_variable(Gogo* gog
 	  if (this->is_global_)
 	    bvar = backend->global_variable((package == NULL
 					     ? gogo->package_name()
-					     : package->name()),
+					     : package->package_name()),
 					    (package == NULL
-					     ? gogo->unique_prefix()
-					     : package->unique_prefix()),
+					     ? gogo->pkgpath_symbol()
+					     : package->pkgpath_symbol()),
 					    n,
 					    btype,
 					    package != NULL,
@@ -4556,7 +4575,12 @@ Named_object::message_name() const
 {
   if (this->package_ == NULL)
     return Gogo::message_name(this->name_);
-  std::string ret = Gogo::message_name(this->package_->name());
+  std::string ret;
+  if (this->package_->has_package_name())
+    ret = this->package_->package_name();
+  else
+    ret = this->package_->pkgpath();
+  ret = Gogo::message_name(ret);
   ret += '.';
   ret += Gogo::message_name(this->name_);
   return ret;
@@ -5213,13 +5237,29 @@ Unnamed_label::get_goto(Translate_contex
 
 // Class Package.
 
-Package::Package(const std::string& name, const std::string& unique_prefix,
-		 Location location)
-  : name_(name), unique_prefix_(unique_prefix), bindings_(new Bindings(NULL)),
-    priority_(0), location_(location), used_(false), is_imported_(false),
+Package::Package(const std::string& pkgpath, Location location)
+  : pkgpath_(pkgpath), pkgpath_symbol_(Gogo::pkgpath_for_symbol(pkgpath)),
+    package_name_(), bindings_(new Bindings(NULL)), priority_(0),
+    location_(location), used_(false), is_imported_(false),
     uses_sink_alias_(false)
 {
-  go_assert(!name.empty() && !unique_prefix.empty());
+  go_assert(!pkgpath.empty());
+  
+}
+
+// Set the package name.
+
+void
+Package::set_package_name(const std::string& package_name, Location location)
+{
+  go_assert(!package_name.empty());
+  if (this->package_name_.empty())
+    this->package_name_ = package_name;
+  else if (this->package_name_ != package_name)
+    error_at(location,
+	     "saw two different packages with the same package path %s: %s, %s",
+	     this->pkgpath_.c_str(), this->package_name_.c_str(),
+	     package_name.c_str());
 }
 
 // Set the priority.  We may see multiple priorities for an imported
Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 187103)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -138,16 +138,14 @@ class Gogo
   is_main_package() const;
 
   // If necessary, adjust the name to use for a hidden symbol.  We add
-  // a prefix of the package name, so that hidden symbols in different
-  // packages do not collide.
+  // the package name, so that hidden symbols in different packages do
+  // not collide.
   std::string
   pack_hidden_name(const std::string& name, bool is_exported) const
   {
     return (is_exported
 	    ? name
-	    : ('.' + this->unique_prefix()
-	       + '.' + this->package_name()
-	       + '.' + name));
+	    : '.' + this->pkgpath() + '.' + name);
   }
 
   // Unpack a name which may have been hidden.  Returns the
@@ -161,9 +159,9 @@ class Gogo
   is_hidden_name(const std::string& name)
   { return name[0] == '.'; }
 
-  // Return the package prefix of a hidden name.
+  // Return the package path of a hidden name.
   static std::string
-  hidden_name_prefix(const std::string& name)
+  hidden_name_pkgpath(const std::string& name)
   {
     go_assert(Gogo::is_hidden_name(name));
     return name.substr(1, name.rfind('.') - 1);
@@ -183,13 +181,30 @@ class Gogo
 	    && name[name.length() - 2] == '.');
   }
 
-  // Return the unique prefix to use for all exported symbols.
+  // Convert a pkgpath into a string suitable for a symbol
+  static std::string
+  pkgpath_for_symbol(const std::string& pkgpath);
+
+  // Return the package path to use for reflect.Type.PkgPath.
+  const std::string&
+  pkgpath() const;
+
+  // Return the package path to use for a symbol name.
   const std::string&
-  unique_prefix() const;
+  pkgpath_symbol() const;
+
+  // Set the package path from a command line option.
+  void
+  set_pkgpath(const std::string&);
 
-  // Set the unique prefix.
+  // Set the prefix from a command line option.
   void
-  set_unique_prefix(const std::string&);
+  set_prefix(const std::string&);
+
+  // Return whether pkgpath was set from a command line option.
+  bool
+  pkgpath_from_option() const
+  { return this->pkgpath_from_option_; }
 
   // Return the priority to use for the package we are compiling.
   // This is two more than the largest priority of any package we
@@ -229,7 +244,7 @@ class Gogo
   Package*
   add_imported_package(const std::string& real_name, const std::string& alias,
 		       bool is_alias_exported,
-		       const std::string& unique_prefix,
+		       const std::string& pkgpath,
 		       Location location,
 		       bool* padd_to_globals);
 
@@ -237,8 +252,7 @@ class Gogo
   // This returns the Package structure for the package, creating if
   // it necessary.
   Package*
-  register_package(const std::string& name, const std::string& unique_prefix,
-		   Location);
+  register_package(const std::string& pkgpath, Location);
 
   // Start compiling a function.  ADD_METHOD_TO_TYPE is true if a
   // method function should be added to the type of its receiver.
@@ -609,11 +623,6 @@ class Gogo
   void
   import_unsafe(const std::string&, bool is_exported, Location);
 
-  // Add a new imported package.
-  Named_object*
-  add_package(const std::string& real_name, const std::string& alias,
-	      const std::string& unique_prefix, Location location);
-
   // Return the current binding contour.
   Bindings*
   current_bindings();
@@ -711,10 +720,18 @@ class Gogo
   std::string init_fn_name_;
   // A list of import control variables for packages that we import.
   std::set<Import_init> imported_init_fns_;
-  // The unique prefix used for all global symbols.
-  std::string unique_prefix_;
-  // Whether an explicit unique prefix was set by -fgo-prefix.
-  bool unique_prefix_specified_;
+  // The package path used for reflection data.
+  std::string pkgpath_;
+  // The package path to use for a symbol name.
+  std::string pkgpath_symbol_;
+  // The prefix to use for symbols, from the -fgo-prefix option.
+  std::string prefix_;
+  // Whether pkgpath_ has been set.
+  bool pkgpath_set_;
+  // Whether an explicit package path was set by -fgo-pkgpath.
+  bool pkgpath_from_option_;
+  // Whether an explicit prefix was set by -fgo-prefix.
+  bool prefix_from_option_;
   // A list of types to verify.
   std::vector<Type*> verify_types_;
   // A list of interface types defined while parsing.
@@ -2409,28 +2426,37 @@ class Unnamed_label
 class Package
 {
  public:
-  Package(const std::string& name, const std::string& unique_prefix,
-	  Location location);
+  Package(const std::string& pkgpath, Location location);
 
-  // The real name of this package.  This may be different from the
-  // name in the associated Named_object if the import statement used
-  // an alias.
+  // Get the package path used for all symbols exported from this
+  // package.
   const std::string&
-  name() const
-  { return this->name_; }
+  pkgpath() const
+  { return this->pkgpath_; }
+
+  // Return the package path to use for a symbol name.
+  const std::string&
+  pkgpath_symbol() const
+  { return this->pkgpath_symbol_; }
 
   // Return the location of the import statement.
   Location
   location() const
   { return this->location_; }
 
-  // Get the unique prefix used for all symbols exported from this
-  // package.
+  // Return whether we know the name of this package yet.
+  bool
+  has_package_name() const
+  { return !this->package_name_.empty(); }
+
+  // The name that this package uses in its package clause.  This may
+  // be different from the name in the associated Named_object if the
+  // import statement used an alias.
   const std::string&
-  unique_prefix() const
+  package_name() const
   {
-    go_assert(!this->unique_prefix_.empty());
-    return this->unique_prefix_;
+    go_assert(!this->package_name_.empty());
+    return this->package_name_;
   }
 
   // The priority of this package.  The init function of packages with
@@ -2500,8 +2526,12 @@ class Package
   lookup(const std::string& name) const
   { return this->bindings_->lookup(name); }
 
-  // Set the location of the package.  This is used if it is seen in a
-  // different import before it is really imported.
+  // Set the name of the package.
+  void
+  set_package_name(const std::string& name, Location);
+
+  // Set the location of the package.  This is used to record the most
+  // recent import location.
   void
   set_location(Location location)
   { this->location_ = location; }
@@ -2537,10 +2567,13 @@ class Package
   determine_types();
 
  private:
-  // The real name of this package.
-  std::string name_;
-  // The unique prefix for all exported global symbols.
-  std::string unique_prefix_;
+  // The package path for type reflection data.
+  std::string pkgpath_;
+  // The package path for symbol names.
+  std::string pkgpath_symbol_;
+  // The name that this package uses in the package clause.  This may
+  // be the empty string if it is not yet known.
+  std::string package_name_;
   // The names in this package.
   Bindings* bindings_;
   // The priority of this package.  A package has a priority higher
Index: gcc/go/gofrontend/go.cc
===================================================================
--- gcc/go/gofrontend/go.cc	(revision 187020)
+++ gcc/go/gofrontend/go.cc	(working copy)
@@ -13,11 +13,6 @@
 #include "backend.h"
 #include "gogo.h"
 
-// The unique prefix to use for exported symbols.  This is set during
-// option processing.
-
-static std::string unique_prefix;
-
 // The data structures we build to represent the file.
 static Gogo* gogo;
 
@@ -25,38 +20,22 @@ static Gogo* gogo;
 
 GO_EXTERN_C
 void
-go_create_gogo(int int_type_size, int pointer_size)
+go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
+	       const char *prefix)
 {
   go_assert(::gogo == NULL);
   Linemap* linemap = go_get_linemap();
   ::gogo = new Gogo(go_get_backend(), linemap, int_type_size, pointer_size);
-  if (!unique_prefix.empty())
-    ::gogo->set_unique_prefix(unique_prefix);
+
+  if (pkgpath != NULL)
+    ::gogo->set_pkgpath(pkgpath);
+  else if (prefix != NULL)
+    ::gogo->set_prefix(prefix);
 
   // FIXME: This should be in the gcc dependent code.
   ::gogo->define_builtin_function_trees();
 }
 
-// Set the unique prefix we use for exported symbols.
-
-GO_EXTERN_C
-void
-go_set_prefix(const char* arg)
-{
-  unique_prefix = arg;
-  for (size_t i = 0; i < unique_prefix.length(); ++i)
-    {
-      char c = unique_prefix[i];
-      if ((c >= 'a' && c <= 'z')
-	  || (c >= 'A' && c <= 'Z')
-	  || (c >= '0' && c <= '9')
-	  || c == '_')
-	;
-      else
-	unique_prefix[i] = '_';
-    }
-}
-
 // Parse the input files.
 
 GO_EXTERN_C
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc	(revision 187176)
+++ gcc/go/gofrontend/parse.cc	(working copy)
@@ -323,13 +323,13 @@ Parse::type_name(bool issue_error)
 	  && package->name() != this->gogo_->package_name())
 	{
 	  // Check whether the name is there but hidden.
-	  std::string s = ('.' + package->package_value()->unique_prefix()
-			   + '.' + package->package_value()->name()
+	  std::string s = ('.' + package->package_value()->pkgpath()
 			   + '.' + name);
 	  named_object = package->package_value()->lookup(s);
 	  if (named_object != NULL)
 	    {
-	      const std::string& packname(package->package_value()->name());
+	      Package* p = package->package_value();
+	      const std::string& packname(p->package_name());
 	      error_at(location, "invalid reference to hidden type %<%s.%s%>",
 		       Gogo::message_name(packname).c_str(),
 		       Gogo::message_name(name).c_str());
@@ -345,7 +345,7 @@ Parse::type_name(bool issue_error)
 	named_object = this->gogo_->add_unknown_name(name, location);
       else
 	{
-	  const std::string& packname(package->package_value()->name());
+	  const std::string& packname(package->package_value()->package_name());
 	  error_at(location, "reference to undefined identifier %<%s.%s%>",
 		   Gogo::message_name(packname).c_str(),
 		   Gogo::message_name(name).c_str());
@@ -2384,7 +2384,7 @@ Parse::operand(bool may_be_sink)
 	  {
 	    go_assert(package != NULL);
 	    error_at(location, "invalid reference to hidden type %<%s.%s%>",
-		     Gogo::message_name(package->name()).c_str(),
+		     Gogo::message_name(package->package_name()).c_str(),
 		     Gogo::message_name(id).c_str());
 	    return Expression::make_error(location);
 	  }
@@ -2394,7 +2394,7 @@ Parse::operand(bool may_be_sink)
 	  {
 	    if (package != NULL)
 	      {
-		std::string n1 = Gogo::message_name(package->name());
+		std::string n1 = Gogo::message_name(package->package_name());
 		std::string n2 = Gogo::message_name(id);
 		if (!is_exported)
 		  error_at(location,
Index: gcc/go/gofrontend/unsafe.cc
===================================================================
--- gcc/go/gofrontend/unsafe.cc	(revision 187020)
+++ gcc/go/gofrontend/unsafe.cc	(working copy)
@@ -22,7 +22,7 @@ Gogo::import_unsafe(const std::string& l
   bool add_to_globals;
   Package* package = this->add_imported_package("unsafe", local_name,
 						is_local_name_exported,
-						"libgo_unsafe",
+						"libgo_unsafe.unsafe",
 						location, &add_to_globals);
 
   if (package == NULL)
Index: gcc/go/gofrontend/export.cc
===================================================================
--- gcc/go/gofrontend/export.cc	(revision 187020)
+++ gcc/go/gofrontend/export.cc	(working copy)
@@ -33,7 +33,7 @@ const int Export::v1_checksum_len;
 // Constructor.
 
 Export::Export(Stream* stream)
-  : stream_(stream), type_refs_(), type_index_(1)
+  : stream_(stream), type_refs_(), type_index_(1), packages_()
 {
 }
 
@@ -91,7 +91,7 @@ should_export(Named_object* no)
 
 void
 Export::export_globals(const std::string& package_name,
-		       const std::string& unique_prefix,
+		       const std::string& pkgpath,
 		       int package_priority,
 		       const std::map<std::string, Package*>& imports,
 		       const std::string& import_init_fn,
@@ -140,9 +140,9 @@ Export::export_globals(const std::string
   this->write_string(package_name);
   this->write_c_string(";\n");
 
-  // The unique prefix.  This prefix is used for all global symbols.
-  this->write_c_string("prefix ");
-  this->write_string(unique_prefix);
+  // The package path, used for all global symbols.
+  this->write_c_string("pkgpath ");
+  this->write_string(pkgpath);
   this->write_c_string(";\n");
 
   // The package priority.
@@ -209,12 +209,14 @@ Export::write_imports(const std::map<std
        ++p)
     {
       this->write_c_string("import ");
-      this->write_string(p->second->name());
+      this->write_string(p->second->package_name());
       this->write_c_string(" ");
-      this->write_string(p->second->unique_prefix());
+      this->write_string(p->second->pkgpath());
       this->write_c_string(" \"");
       this->write_string(p->first);
       this->write_c_string("\";\n");
+
+      this->packages_.insert(p->second);
     }
 }
 
@@ -333,7 +335,7 @@ Export::write_type(const Type* type)
 	{
 	  // The builtin types should have been predefined.
 	  go_assert(!Linemap::is_predeclared_location(named_type->location())
-		     || (named_type->named_object()->package()->name()
+		     || (named_type->named_object()->package()->package_name()
 			 == "unsafe"));
 	  named_object = named_type->named_object();
 	}
@@ -345,15 +347,26 @@ Export::write_type(const Type* type)
       std::string s = "\"";
       if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
 	{
-	  s += package->unique_prefix();
-	  s += '.';
-	  s += package->name();
+	  s += package->pkgpath();
 	  s += '.';
 	}
       s += named_object->name();
       s += "\" ";
       this->write_string(s);
 
+      // It is possible that this type was imported indirectly, and is
+      // not in a package in the import list.  If we have not
+      // mentioned this package before, write out the package name
+      // here so that any package importing this one will know it.
+      if (package != NULL
+	  && this->packages_.find(package) == this->packages_.end())
+	{
+	  this->write_c_string("\"");
+	  this->write_string(package->package_name());
+	  this->packages_.insert(package);
+	  this->write_c_string("\" ");
+	}
+
       // 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.
Index: gcc/go/gofrontend/export.h
===================================================================
--- gcc/go/gofrontend/export.h	(revision 187020)
+++ gcc/go/gofrontend/export.h	(working copy)
@@ -117,7 +117,7 @@ class Export : public String_dump
   // Export the identifiers in BINDINGS which are marked for export.
   // The exporting is done via a series of calls to THIS->STREAM_.  If
   // is nothing to export, this->stream_->write will not be called.
-  // UNIQUE_PREFIX is a prefix for all global symbols.
+  // PKGPATH is the package path.
   // PACKAGE_PRIORITY is the priority to use for this package.
   // IMPORT_INIT_FN is the name of the import initialization function
   // for this package; it will be empty if none is needed.
@@ -125,7 +125,7 @@ class Export : public String_dump
   // imported packages.
   void
   export_globals(const std::string& package_name,
-		 const std::string& unique_prefix,
+		 const std::string& pkgpath,
 		 int package_priority,
 		 const std::map<std::string, Package*>& imports,
 		 const std::string& import_init_fn,
@@ -182,6 +182,8 @@ class Export : public String_dump
   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.
Index: gcc/go/gofrontend/gogo-tree.cc
===================================================================
--- gcc/go/gofrontend/gogo-tree.cc	(revision 187103)
+++ gcc/go/gofrontend/gogo-tree.cc	(working copy)
@@ -260,9 +260,7 @@ Gogo::get_init_fn_name()
 	}
       else
 	{
-	  std::string s = this->unique_prefix();
-	  s.append(1, '.');
-	  s.append(this->package_name());
+	  std::string s = this->pkgpath_symbol();
 	  s.append("..import");
 	  this->init_fn_name_ = s;
 	}
@@ -984,7 +982,7 @@ Named_object::get_id(Gogo* gogo)
       if (this->package_ == NULL)
 	package_name = gogo->package_name();
       else
-	package_name = this->package_->name();
+	package_name = this->package_->package_name();
 
       decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
 
@@ -1277,9 +1275,15 @@ Function::get_or_make_decl(Gogo* gogo, N
 		   || this->type_->is_method())
 	    {
 	      TREE_PUBLIC(decl) = 1;
-	      std::string asm_name = gogo->unique_prefix();
+	      std::string asm_name = gogo->pkgpath_symbol();
 	      asm_name.append(1, '.');
-	      asm_name.append(IDENTIFIER_POINTER(id), IDENTIFIER_LENGTH(id));
+	      asm_name.append(Gogo::unpack_hidden_name(no->name()));
+	      if (this->type_->is_method())
+		{
+		  asm_name.append(1, '.');
+		  Type* rtype = this->type_->receiver()->type();
+		  asm_name.append(rtype->mangled_name(gogo));
+		}
 	      SET_DECL_ASSEMBLER_NAME(decl,
 				      get_identifier_from_string(asm_name));
 	    }
@@ -1382,10 +1386,16 @@ Function_declaration::get_or_make_decl(G
 	  if (this->asm_name_.empty())
 	    {
 	      std::string asm_name = (no->package() == NULL
-				      ? gogo->unique_prefix()
-				      : no->package()->unique_prefix());
+				      ? gogo->pkgpath_symbol()
+				      : no->package()->pkgpath_symbol());
 	      asm_name.append(1, '.');
-	      asm_name.append(IDENTIFIER_POINTER(id), IDENTIFIER_LENGTH(id));
+	      asm_name.append(Gogo::unpack_hidden_name(no->name()));
+	      if (this->fntype_->is_method())
+		{
+		  asm_name.append(1, '.');
+		  Type* rtype = this->fntype_->receiver()->type();
+		  asm_name.append(rtype->mangled_name(gogo));
+		}
 	      SET_DECL_ASSEMBLER_NAME(decl,
 				      get_identifier_from_string(asm_name));
 	    }
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 187020)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -321,16 +321,16 @@ class Backend
   error_variable() = 0;
 
   // Create a global variable.  PACKAGE_NAME is the name of the
-  // package where the variable is defined.  UNIQUE_PREFIX is the
-  // prefix for that package, from the -fgo-prefix option.  NAME is
-  // the name of the variable.  BTYPE is the type of the variable.
-  // IS_EXTERNAL is true if the variable is defined in some other
-  // package.  IS_HIDDEN is true if the variable is not exported (name
-  // begins with a lower case letter).  LOCATION is where the variable
-  // was defined.
+  // package where the variable is defined.  PKGPATH is the package
+  // path for that package, from the -fgo-pkgpath or -fgo-prefix
+  // option.  NAME is the name of the variable.  BTYPE is the type of
+  // the variable.  IS_EXTERNAL is true if the variable is defined in
+  // some other package.  IS_HIDDEN is true if the variable is not
+  // exported (name begins with a lower case letter).  LOCATION is
+  // where the variable was defined.
   virtual Bvariable*
   global_variable(const std::string& package_name,
-		  const std::string& unique_prefix,
+		  const std::string& pkgpath,
 		  const std::string& name,
 		  Btype* btype,
 		  bool is_external,
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 187020)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -1301,15 +1301,10 @@ Type::type_descriptor_var_name(Gogo* gog
     go_assert(in_function == NULL);
   else
     {
-      const std::string& unique_prefix(no->package() == NULL
-				       ? gogo->unique_prefix()
-				       : no->package()->unique_prefix());
-      const std::string& package_name(no->package() == NULL
-				      ? gogo->package_name()
-				      : no->package()->name());
-      ret.append(unique_prefix);
-      ret.append(1, '.');
-      ret.append(package_name);
+      const std::string& pkgpath(no->package() == NULL
+				 ? gogo->pkgpath_symbol()
+				 : no->package()->pkgpath_symbol());
+      ret.append(pkgpath);
       ret.append(1, '.');
       if (in_function != NULL)
 	{
@@ -1317,7 +1312,20 @@ Type::type_descriptor_var_name(Gogo* gog
 	  ret.append(1, '.');
 	}
     }
-  ret.append(no->name());
+
+  // FIXME: This adds in pkgpath twice for hidden symbols, which is
+  // pointless.
+  const std::string& name(no->name());
+  if (!Gogo::is_hidden_name(name))
+    ret.append(name);
+  else
+    {
+      ret.append(1, '.');
+      ret.append(Gogo::pkgpath_for_symbol(Gogo::hidden_name_pkgpath(name)));
+      ret.append(1, '.');
+      ret.append(Gogo::unpack_hidden_name(name));
+    }
+
   return ret;
 }
 
@@ -1977,15 +1985,10 @@ Type::uncommon_type_constructor(Gogo* go
       else
 	{
 	  const Package* package = no->package();
-	  const std::string& unique_prefix(package == NULL
-					   ? gogo->unique_prefix()
-					   : package->unique_prefix());
-	  const std::string& package_name(package == NULL
-					  ? gogo->package_name()
-					  : package->name());
-	  n.assign(unique_prefix);
-	  n.append(1, '.');
-	  n.append(package_name);
+	  const std::string& pkgpath(package == NULL
+				     ? gogo->pkgpath()
+				     : package->pkgpath());
+	  n.assign(pkgpath);
 	  if (name->in_function() != NULL)
 	    {
 	      n.append(1, '.');
@@ -2096,7 +2099,8 @@ Type::method_constructor(Gogo*, Type* me
     vals->push_back(Expression::make_nil(bloc));
   else
     {
-      s = Expression::make_string(Gogo::hidden_name_prefix(method_name), bloc);
+      s = Expression::make_string(Gogo::hidden_name_pkgpath(method_name),
+				  bloc);
       vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
     }
 
@@ -4668,7 +4672,7 @@ Struct_type::do_type_descriptor(Gogo* go
 	fvals->push_back(Expression::make_nil(bloc));
       else
 	{
-	  std::string n = Gogo::hidden_name_prefix(pf->field_name());
+	  std::string n = Gogo::hidden_name_pkgpath(pf->field_name());
 	  Expression* s = Expression::make_string(n, bloc);
 	  fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
 	}
@@ -7056,7 +7060,7 @@ Interface_type::do_type_descriptor(Gogo*
 	    mvals->push_back(Expression::make_nil(bloc));
 	  else
 	    {
-	      s = Gogo::hidden_name_prefix(pm->name());
+	      s = Gogo::hidden_name_pkgpath(pm->name());
 	      e = Expression::make_string(s, bloc);
 	      mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
 	    }
@@ -7105,11 +7109,15 @@ Interface_type::do_reflection(Gogo* gogo
 	    {
 	      if (!Gogo::is_hidden_name(p->name()))
 		ret->append(p->name());
+	      else if (gogo->pkgpath_from_option())
+		ret->append(p->name().substr(1));
 	      else
 		{
-		  // This matches what the gc compiler does.
-		  std::string prefix = Gogo::hidden_name_prefix(p->name());
-		  ret->append(prefix.substr(prefix.find('.') + 1));
+		  // If no -fgo-pkgpath option, backward compatibility
+		  // for how this used to work before -fgo-pkgpath was
+		  // introduced.
+		  std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
+		  ret->append(pkgpath.substr(pkgpath.find('.') + 1));
 		  ret->push_back('.');
 		  ret->append(Gogo::unpack_hidden_name(p->name()));
 		}
@@ -7939,20 +7947,14 @@ Named_type::do_hash_for_method(Gogo* gog
   // where we are going to be comparing named types for equality.  In
   // other cases, which are cases where the runtime is going to
   // compare hash codes to see if the types are the same, we need to
-  // include the package prefix and name in the hash.
+  // include the pkgpath in the hash.
   if (gogo != NULL && !Gogo::is_hidden_name(name) && !this->is_builtin())
     {
       const Package* package = this->named_object()->package();
       if (package == NULL)
-	{
-	  ret = Type::hash_string(gogo->unique_prefix(), ret);
-	  ret = Type::hash_string(gogo->package_name(), ret);
-	}
+	ret = Type::hash_string(gogo->pkgpath(), ret);
       else
-	{
-	  ret = Type::hash_string(package->unique_prefix(), ret);
-	  ret = Type::hash_string(package->name(), ret);
-	}
+	ret = Type::hash_string(package->pkgpath(), ret);
     }
 
   return ret;
@@ -8324,11 +8326,16 @@ Named_type::do_reflection(Gogo* gogo, st
     }
   if (!this->is_builtin())
     {
+      // We handle -fgo-prefix and -fgo-pkgpath differently here for
+      // compatibility with how the compiler worked before
+      // -fgo-pkgpath was introduced.
       const Package* package = this->named_object_->package();
-      if (package != NULL)
-	ret->append(package->name());
+      if (gogo->pkgpath_from_option())
+	ret->append(package != NULL ? package->pkgpath() : gogo->pkgpath());
       else
-	ret->append(gogo->package_name());
+	ret->append(package != NULL
+		    ? package->package_name()
+		    : gogo->package_name());
       ret->push_back('.');
     }
   if (this->in_function_ != NULL)
@@ -8355,15 +8362,10 @@ Named_type::do_mangled_name(Gogo* gogo, 
     go_assert(this->in_function_ == NULL);
   else
     {
-      const std::string& unique_prefix(no->package() == NULL
-				       ? gogo->unique_prefix()
-				       : no->package()->unique_prefix());
-      const std::string& package_name(no->package() == NULL
-				      ? gogo->package_name()
-				      : no->package()->name());
-      name = unique_prefix;
-      name.append(1, '.');
-      name.append(package_name);
+      const std::string& pkgpath(no->package() == NULL
+				 ? gogo->pkgpath_symbol()
+				 : no->package()->pkgpath_symbol());
+      name = pkgpath;
       name.append(1, '.');
       if (this->in_function_ != NULL)
 	{
@@ -9487,9 +9489,9 @@ Forward_declaration_type::do_mangled_nam
       const Named_object* no = this->named_object();
       std::string name;
       if (no->package() == NULL)
-	name = gogo->package_name();
+	name = gogo->pkgpath_symbol();
       else
-	name = no->package()->name();
+	name = no->package()->pkgpath_symbol();
       name += '.';
       name += Gogo::unpack_hidden_name(no->name());
       char buf[20];
Index: gcc/go/gofrontend/import.cc
===================================================================
--- gcc/go/gofrontend/import.cc	(revision 187111)
+++ gcc/go/gofrontend/import.cc	(working copy)
@@ -281,13 +281,24 @@ Import::import(Gogo* gogo, const std::st
       std::string package_name = this->read_identifier();
       this->require_c_string(";\n");
 
-      this->require_c_string("prefix ");
-      std::string unique_prefix = this->read_identifier();
-      this->require_c_string(";\n");
+      std::string pkgpath;
+      if (this->match_c_string("prefix "))
+	{
+	  this->advance(7);
+	  std::string unique_prefix = this->read_identifier();
+	  this->require_c_string(";\n");
+	  pkgpath = unique_prefix + '.' + package_name;
+	}
+      else
+	{
+	  this->require_c_string("pkgpath ");
+	  pkgpath = this->read_identifier();
+	  this->require_c_string(";\n");
+	}
 
       this->package_ = gogo->add_imported_package(package_name, local_name,
 						  is_local_name_exported,
-						  unique_prefix,
+						  pkgpath,
 						  this->location_,
 						  &this->add_to_globals_);
       if (this->package_ == NULL)
@@ -353,10 +364,18 @@ void
 Import::read_one_import()
 {
   this->require_c_string("import ");
+  std::string package_name = this->read_identifier();
+  this->require_c_string(" ");
+  std::string pkgpath = this->read_identifier();
+  this->require_c_string(" \"");
   Stream* stream = this->stream_;
-  while (stream->peek_char() != ';')
+  while (stream->peek_char() != '"')
     stream->advance(1);
-  this->require_c_string(";\n");
+  this->require_c_string("\";\n");
+
+  Package* p = this->gogo_->register_package(pkgpath,
+					     Linemap::unknown_location());
+  p->set_package_name(package_name, this->location());
 }
 
 // Read the list of import control functions.
@@ -572,55 +591,50 @@ Import::read_type()
   while ((c = stream->get_char()) != '"')
     type_name += c;
 
-  // If this type is in the current package, the name will be
-  // .PREFIX.PACKAGE.NAME or simply NAME with no dots.  Otherwise, a
-  // non-hidden symbol will be PREFIX.PACKAGE.NAME and a hidden symbol
-  // will be .PREFIX.PACKAGE.NAME.
-  std::string package_name;
-  std::string unique_prefix;
+  // If this type is in the package we are currently importing, the
+  // name will be .PKGPATH.NAME or simply NAME with no dots.
+  // Otherwise, a non-hidden symbol will be PKGPATH.NAME and a hidden
+  // symbol will be .PKGPATH.NAME.
+  std::string pkgpath;
   if (type_name.find('.') != std::string::npos)
     {
-      bool is_hidden = false;
       size_t start = 0;
       if (type_name[0] == '.')
-	{
-	  ++start;
-	  is_hidden = true;
-	}
-      size_t dot1 = type_name.find('.', start);
-      size_t dot2;
-      if (dot1 == std::string::npos)
-	dot2 = std::string::npos;
-      else
-	dot2 = type_name.find('.', dot1 + 1);
-      if (dot1 == std::string::npos || dot2 == std::string::npos)
-	{
-	  error_at(this->location_,
-		   ("error at import data at %d: missing dot in type name"),
-		   stream->pos());
-	  stream->set_saw_error();
-	}
-      else
-	{
-	  unique_prefix = type_name.substr(start, dot1 - start);
-	  package_name = type_name.substr(dot1 + 1, dot2 - (dot1 + 1));
-	}
-      if (!is_hidden)
-	type_name.erase(0, dot2 + 1);
+	start = 1;
+      size_t dot = type_name.rfind('.');
+      pkgpath = type_name.substr(start, dot - start);
+      if (type_name[0] != '.')
+	type_name.erase(0, dot + 1);
     }
 
   this->require_c_string(" ");
 
+  // 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.
+  std::string package_name;
+  if (stream->peek_char() == '"')
+    {
+      stream->advance(1);
+      while ((c = stream->get_char()) != '"')
+	package_name += c;
+      this->require_c_string(" ");
+    }
+
   // Declare the type in the appropriate package.  If we haven't seen
   // it before, mark it as invisible.  We declare it before we read
   // the actual definition of the type, since the definition may refer
   // to the type itself.
   Package* package;
-  if (package_name.empty())
+  if (pkgpath.empty() || pkgpath == this->gogo_->pkgpath())
     package = this->package_;
   else
-    package = this->gogo_->register_package(package_name, unique_prefix,
-					    Linemap::unknown_location());
+    {
+      package = this->gogo_->register_package(pkgpath,
+					      Linemap::unknown_location());
+      if (!package_name.empty())
+	package->set_package_name(package_name, this->location());
+    }
 
   Named_object* no = package->bindings()->lookup(type_name);
   if (no == NULL)
@@ -628,8 +642,7 @@ Import::read_type()
   else if (!no->is_type_declaration() && !no->is_type())
     {
       error_at(this->location_, "imported %<%s.%s%> both type and non-type",
-	       Gogo::message_name(package->name()).c_str(),
-	       Gogo::message_name(type_name).c_str());
+	       pkgpath.c_str(), Gogo::message_name(type_name).c_str());
       stream->set_saw_error();
       return Type::make_error_type();
     }
@@ -772,9 +785,7 @@ Import::read_name()
   if (ret == "?")
     ret.clear();
   else if (!Lex::is_exported_name(ret))
-    ret = ('.' + this->package_->unique_prefix()
-	   + '.' + this->package_->name()
-	   + '.' + ret);
+    ret = '.' + this->package_->pkgpath() + '.' + ret;
   return ret;
 }
 
Index: gcc/go/go-lang.c
===================================================================
--- gcc/go/go-lang.c	(revision 187020)
+++ gcc/go/go-lang.c	(working copy)
@@ -81,6 +81,11 @@ struct GTY(()) language_function
   int dummy;
 };
 
+/* Option information we need to pass to go_create_gogo.  */
+
+static const char *go_pkgpath = NULL;
+static const char *go_prefix = NULL;
+
 /* Language hooks.  */
 
 static bool
@@ -96,7 +101,7 @@ go_langhook_init (void)
      to, e.g., unsigned_char_type_node) but before calling
      build_common_builtin_nodes (because it calls, indirectly,
      go_type_for_size).  */
-  go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE);
+  go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix);
 
   build_common_builtin_nodes ();
 
@@ -227,8 +232,12 @@ go_langhook_handle_option (
       ret = go_enable_optimize (arg) ? true : false;
       break;
 
+    case OPT_fgo_pkgpath_:
+      go_pkgpath = arg;
+      break;
+
     case OPT_fgo_prefix_:
-      go_set_prefix (arg);
+      go_prefix = arg;
       break;
 
     default:
Index: gcc/go/go-c.h
===================================================================
--- gcc/go/go-c.h	(revision 187020)
+++ gcc/go/go-c.h	(working copy)
@@ -38,11 +38,11 @@ extern "C"
 
 extern int go_enable_dump (const char*);
 extern int go_enable_optimize (const char*);
-extern void go_set_prefix (const char*);
 
 extern void go_add_search_path (const char*);
 
-extern void go_create_gogo (int int_type_size, int pointer_size);
+extern void go_create_gogo (int int_type_size, int pointer_size,
+			    const char* pkgpath, const char *prefix);
 
 extern void go_parse_input_files (const char**, unsigned int,
 				  bool only_check_syntax,

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]