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
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);
&& 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&
- unique_prefix() const;
+ pkgpath() const;
- // Set the unique prefix.
+ // 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
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);
// 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.
Block*
finish_block(Location);
+ // Declare an erroneous name. This is used to avoid knock-on errors
+ // after a parsing error.
+ Named_object*
+ add_erroneous_name(const std::string& name);
+
// Declare an unknown name. This is used while parsing. The name
// must be resolved by the end of the parse. Unknown names are
// always added at the package level.
Named_object*
declare_function(const std::string&, Function_type*, Location);
+ // Declare a function at the package level. This is used for
+ // functions generated for a type.
+ Named_object*
+ declare_package_function(const std::string&, Function_type*, Location);
+
// Add a label.
Label*
add_label_definition(const std::string&, Location);
Named_object*
add_sink();
+ // Add a type which needs to be verified. This is used for sink
+ // types, just to give appropriate error messages.
+ void
+ add_type_to_verify(Type* type);
+
// Add a named object to the current namespace. This is used for
// import . "package".
void
add_named_object(Named_object*);
+ // Mark all local variables in current bindings as used. This is
+ // used when there is a parse error to avoid useless errors.
+ void
+ mark_locals_used();
+
// Return a name to use for a thunk function. A thunk function is
// one we create during the compilation, for a go statement or a
// defer statement or a method expression.
void
clear_file_scope();
+ // Record that VAR1 must be initialized after VAR2. This is used
+ // when VAR2 does not appear in VAR1's INIT or PREINIT.
+ void
+ record_var_depends_on(Variable* var1, Named_object* var2)
+ {
+ go_assert(this->var_deps_.find(var1) == this->var_deps_.end());
+ this->var_deps_[var1] = var2;
+ }
+
+ // Return the variable that VAR depends on, or NULL if none.
+ Named_object*
+ var_depends_on(Variable* var) const
+ {
+ Var_deps::const_iterator p = this->var_deps_.find(var);
+ return p != this->var_deps_.end() ? p->second : NULL;
+ }
+
+ // Queue up a type-specific function to be written out. This is
+ // used when a type-specific function is needed when not at the top
+ // level.
+ void
+ queue_specific_type_function(Type* type, Named_type* name,
+ const std::string& hash_name,
+ Function_type* hash_fntype,
+ const std::string& equal_name,
+ Function_type* equal_fntype);
+
+ // Write out queued specific type functions.
+ void
+ write_specific_type_functions();
+
+ // Whether we are done writing out specific type functions.
+ bool
+ specific_type_functions_are_written() const
+ { return this->specific_type_functions_are_written_; }
+
// Traverse the tree. See the Traverse class.
void
traverse(Traverse*);
// Receive a value from a channel.
static tree
- receive_from_channel(tree type_tree, tree channel, bool for_select,
+ receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel,
Location);
- // Return a tree for receiving an integer on a channel.
- static tree
- receive_as_64bit_integer(tree type, tree channel, bool blocking,
- bool for_select);
-
// Make a trampoline which calls FNADDR passing CLOSURE.
tree
make_trampoline(tree fnaddr, tree closure, Location);
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();
// Type used to map package names to packages.
typedef std::map<std::string, Package*> Packages;
- // Type used to map special names in the sys package.
- typedef std::map<std::string, std::string> Sys_names;
+ // Type used to map variables to the function calls that set them.
+ // This is used for initialization dependency analysis.
+ typedef std::map<Variable*, Named_object*> Var_deps;
+
+ // Type used to queue writing a type specific function.
+ struct Specific_type_function
+ {
+ Type* type;
+ Named_type* name;
+ std::string hash_name;
+ Function_type* hash_fntype;
+ std::string equal_name;
+ Function_type* equal_fntype;
+
+ Specific_type_function(Type* atype, Named_type* aname,
+ const std::string& ahash_name,
+ Function_type* ahash_fntype,
+ const std::string& aequal_name,
+ Function_type* aequal_fntype)
+ : type(atype), name(aname), hash_name(ahash_name),
+ hash_fntype(ahash_fntype), equal_name(aequal_name),
+ equal_fntype(aequal_fntype)
+ { }
+ };
// The backend generator.
Backend* backend_;
Packages packages_;
// The functions named "init", if there are any.
std::vector<Named_object*> init_functions_;
+ // A mapping from variables to the function calls that initialize
+ // them, if it is not stored in the variable's init or preinit.
+ // This is used for dependency analysis.
+ Var_deps var_deps_;
// Whether we need a magic initialization function.
bool need_init_fn_;
// The name of the magic initialization function.
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.
std::vector<Interface_type*> interface_types_;
+ // Type specific functions to write out.
+ std::vector<Specific_type_function*> specific_type_functions_;
+ // Whether we are done writing out specific type functions.
+ bool specific_type_functions_are_written_;
// Whether named types have been converted.
bool named_types_are_converted_;
};
// Return whether the type is defined yet.
bool
- has_type() const
- { return this->type_ != NULL; }
+ has_type() const;
// Get the initial value.
Expression*
this->is_varargs_parameter_ = true;
}
+ // Return whether the variable has been used.
+ bool
+ is_used() const
+ { return this->is_used_; }
+
+ // Mark that the variable has been used.
+ void
+ set_is_used()
+ { this->is_used_ = true; }
+
// Clear the initial value; used for error handling.
void
clear_init()
bool is_receiver_ : 1;
// Whether this is the varargs parameter of a function.
bool is_varargs_parameter_ : 1;
+ // Whether this variable is ever referenced.
+ bool is_used_ : 1;
// Whether something takes the address of this variable. For a
// local variable this implies that the variable has to be on the
// heap.
// Add a method declaration to this type.
Named_object*
- add_method_declaration(const std::string& name, Function_type* type,
- Location location);
+ add_method_declaration(const std::string& name, Package*,
+ Function_type* type, Location location);
// Return whether any methods were defined.
bool
{
// An uninitialized Named_object. We should never see this.
NAMED_OBJECT_UNINITIALIZED,
+ // An erroneous name. This indicates a parse error, to avoid
+ // later errors about undefined references.
+ NAMED_OBJECT_ERRONEOUS,
// An unknown name. This is used for forward references. In a
// correct program, these will all be resolved by the end of the
// parse.
// Classifiers.
bool
+ is_erroneous() const
+ { return this->classification_ == NAMED_OBJECT_ERRONEOUS; }
+
+ bool
is_unknown() const
{ return this->classification_ == NAMED_OBJECT_UNKNOWN; }
// Creators.
static Named_object*
+ make_erroneous_name(const std::string& name)
+ { return new Named_object(name, NULL, NAMED_OBJECT_ERRONEOUS); }
+
+ static Named_object*
make_unknown_name(const std::string& name, Location);
static Named_object*
Bindings(Bindings* enclosing);
+ // Add an erroneous name.
+ Named_object*
+ add_erroneous_name(const std::string& name)
+ { return this->add_named_object(Named_object::make_erroneous_name(name)); }
+
// Add an unknown name.
Named_object*
add_unknown_name(const std::string& name, Location location)
void
remove_binding(Named_object*);
+ // Mark all variables as used. This is used for some types of parse
+ // error.
+ void
+ mark_locals_used();
+
// Traverse the tree. See the Traverse class.
int
traverse(Traverse*, bool is_global);
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
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; }
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
type(Type*);
private:
- typedef Unordered_set_hash(const Type*, Type_hash_identical,
- Type_identical) Types_seen;
+ // A hash table for types we have seen during this traversal. Note
+ // that this uses the default hash functions for pointers rather
+ // than Type_hash_identical and Type_identical. This is because for
+ // traversal we care about seeing a specific type structure. If
+ // there are two separate instances of identical types, we want to
+ // traverse both.
+ typedef Unordered_set(const Type*) Types_seen;
typedef Unordered_set(const Expression*) Expressions_seen;
// Channel capacity out of bounds in make: negative or overflow.
static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9;
+// Division by zero.
+static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10;
+
// This is used by some of the langhooks.
extern Gogo* go_get_gogo();