compiler: Add -fgo-pkgpath option.

* 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.

From-SVN: r187357
This commit is contained in:
Ian Lance Taylor 2012-05-09 23:30:17 +00:00 committed by Ian Lance Taylor
parent abbaf67670
commit 3ded8ee74a
17 changed files with 460 additions and 323 deletions

View File

@ -1,3 +1,19 @@
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.
2012-04-23 Ian Lance Taylor <iant@google.com>
* go-lang.c (go_langhook_init): Set MPFR precision to 256.

View File

@ -12,7 +12,7 @@
@include gcc-common.texi
@c Copyright years for this manual.
@set copyrights-go 2010
@set copyrights-go 2010, 2011, 2012
@copying
@c man begin COPYRIGHT
@ -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

View File

@ -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,

View File

@ -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 type)
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::string& package_name,
{
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;

View File

@ -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:

View File

@ -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,

View File

@ -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& package_name,
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::string, Package*>& imports)
++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.

View File

@ -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.

View File

@ -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

View File

@ -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;
}
@ -985,7 +983,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_);
@ -1278,9 +1276,15 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
|| 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));
}
@ -1383,10 +1387,16 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
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));
}

View File

@ -36,8 +36,12 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
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* linemap, int int_type_size,
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";
// 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->package_ = this->register_package(package_name, this->unique_prefix_,
location);
this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_);
// 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_);
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& package_name,
}
// 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& filename,
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& filename,
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::string& real_name,
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* gogo, Named_object* function,
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_context* context, Location location)
// 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

View File

@ -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.
const std::string&
unique_prefix() const;
// Convert a pkgpath into a string suitable for a symbol
static std::string
pkgpath_for_symbol(const std::string& pkgpath);
// Set the unique prefix.
// 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&
pkgpath_symbol() const;
// Set the package path from a command line option.
void
set_unique_prefix(const std::string&);
set_pkgpath(const std::string&);
// Set the prefix from a command line option.
void
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

View File

@ -281,13 +281,24 @@ Import::import(Gogo* gogo, const std::string& local_name,
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;
}

View File

@ -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,

View File

@ -1301,15 +1301,10 @@ Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
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* gogo, Named_type* nt)
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* gogo, Type* uncommon_type,
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* method_type,
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* gogo, Named_type* name)
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* gogo, Named_type* name)
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, std::string* ret) const
{
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* gogo) const
// 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, std::string* ret) const
}
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, std::string* ret) const
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_name(Gogo* gogo, std::string* ret) const
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];

View File

@ -22,7 +22,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
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)

View File

@ -1,6 +1,6 @@
; lang.opt -- Options for the gcc Go front end.
; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
@ -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