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);
// 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 unique_prefix_;
// Whether an explicit unique prefix was set by -fgo-prefix.
bool unique_prefix_specified_;
+ // 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);
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();