OSDN Git Service

compiler: Fix order of initialization bug with global var a, b = f().
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / gogo.h
index 788c80a..4990bf2 100644 (file)
@@ -7,7 +7,10 @@
 #ifndef GO_GOGO_H
 #define GO_GOGO_H
 
+#include "go-linemap.h"
+
 class Traverse;
+class Statement_inserter;
 class Type;
 class Type_hash_identical;
 class Type_equal;
@@ -21,6 +24,7 @@ class Temporary_statement;
 class Block;
 class Function;
 class Bindings;
+class Bindings_snapshot;
 class Package;
 class Variable;
 class Pointer_type;
@@ -109,20 +113,25 @@ class Gogo
  public:
   // Create the IR, passing in the sizes of the types "int" and
   // "uintptr" in bits.
-  Gogo(Backend* backend, int int_type_size, int pointer_size);
+  Gogo(Backend* backend, Linemap *linemap, int int_type_size, int pointer_size);
 
   // Get the backend generator.
   Backend*
   backend()
   { return this->backend_; }
 
+  // Get the Location generator.
+  Linemap*
+  linemap()
+  { return this->linemap_; }
+
   // Get the package name.
   const std::string&
   package_name() const;
 
   // Set the package name.
   void
-  set_package_name(const std::string&, source_location);
+  set_package_name(const std::string&, Location);
 
   // Return whether this is the "main" package.
   bool
@@ -193,7 +202,7 @@ class Gogo
   // the declarations are added to the global scope.
   void
   import_package(const std::string& filename, const std::string& local_name,
-                bool is_local_name_exported, source_location);
+                bool is_local_name_exported, Location);
 
   // Whether we are the global binding level.
   bool
@@ -221,7 +230,7 @@ class Gogo
   add_imported_package(const std::string& real_name, const std::string& alias,
                       bool is_alias_exported,
                       const std::string& unique_prefix,
-                      source_location location,
+                      Location location,
                       bool* padd_to_globals);
 
   // Register a package.  This package may or may not be imported.
@@ -229,48 +238,69 @@ class Gogo
   // it necessary.
   Package*
   register_package(const std::string& name, const std::string& unique_prefix,
-                  source_location);
+                  Location);
 
   // Start compiling a function.  ADD_METHOD_TO_TYPE is true if a
   // method function should be added to the type of its receiver.
   Named_object*
   start_function(const std::string& name, Function_type* type,
-                bool add_method_to_type, source_location);
+                bool add_method_to_type, Location);
 
   // Finish compiling a function.
   void
-  finish_function(source_location);
+  finish_function(Location);
 
   // Return the current function.
   Named_object*
   current_function() const;
 
+  // Return the current block.
+  Block*
+  current_block();
+
   // Start a new block.  This is not initially associated with a
   // function.
   void
-  start_block(source_location);
+  start_block(Location);
 
   // Finish the current block and return it.
   Block*
-  finish_block(source_location);
+  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*
-  add_unknown_name(const std::string& name, source_location);
+  add_unknown_name(const std::string& name, Location);
 
   // Declare a function.
   Named_object*
-  declare_function(const std::string&, Function_type*, source_location);
+  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&, source_location);
+  add_label_definition(const std::string&, Location);
 
-  // Add a label reference.
+  // Add a label reference.  ISSUE_GOTO_ERRORS is true if we should
+  // report errors for a goto from the current location to the label
+  // location.
   Label*
-  add_label_reference(const std::string&);
+  add_label_reference(const std::string&, Location,
+                     bool issue_goto_errors);
+
+  // Return a snapshot of the current binding state.
+  Bindings_snapshot*
+  bindings_snapshot(Location);
 
   // Add a statement to the current block.
   void
@@ -278,7 +308,7 @@ class Gogo
 
   // Add a block to the current block.
   void
-  add_block(Block*, source_location);
+  add_block(Block*, Location);
 
   // Add a constant.
   Named_object*
@@ -286,7 +316,7 @@ class Gogo
 
   // Add a type.
   void
-  add_type(const std::string&, Type*, source_location);
+  add_type(const std::string&, Type*, Location);
 
   // Add a named type.  This is used for builtin types, and to add an
   // imported type to the global scope.
@@ -295,12 +325,12 @@ class Gogo
 
   // Declare a type.
   Named_object*
-  declare_type(const std::string&, source_location);
+  declare_type(const std::string&, Location);
 
   // Declare a type at the package level.  This is used when the
   // parser sees an unknown name where a type name is required.
   Named_object*
-  declare_package_type(const std::string&, source_location);
+  declare_package_type(const std::string&, Location);
 
   // Define a type which was already declared.
   void
@@ -314,11 +344,21 @@ class Gogo
   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.
@@ -344,6 +384,42 @@ class Gogo
   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*);
@@ -366,7 +442,7 @@ class Gogo
 
   // Lower an expression.
   void
-  lower_expression(Named_object* function, Expression**);
+  lower_expression(Named_object* function, Statement_inserter*, Expression**);
 
   // Lower a constant.
   void
@@ -421,6 +497,10 @@ class Gogo
   void
   simplify_thunk_statements();
 
+  // Dump AST if -fgo-dump-ast is set 
+  void
+  dump_ast(const char* basename);
+
   // Convert named types to the backend representation.
   void
   convert_named_types();
@@ -439,18 +519,22 @@ class Gogo
   void
   write_globals();
 
+  // Create trees for implicit builtin functions.
+  void
+  define_builtin_function_trees();
+
   // Build a call to a builtin function.  PDECL should point to a NULL
   // initialized static pointer which will hold the fndecl.  NAME is
   // the name of the function.  NARGS is the number of arguments.
   // RETTYPE is the return type.  It is followed by NARGS pairs of
   // type and argument (both trees).
   static tree
-  call_builtin(tree* pdecl, source_location, const char* name, int nargs,
+  call_builtin(tree* pdecl, Location, const char* name, int nargs,
               tree rettype, ...);
 
   // Build a call to the runtime error function.
   static tree
-  runtime_error(int code, source_location);
+  runtime_error(int code, Location);
 
   // Build a builtin struct with a list of fields.
   static tree
@@ -461,16 +545,6 @@ class Gogo
   static void
   mark_fndecl_as_builtin_library(tree fndecl);
 
-  // Build the type of the struct that holds a slice for the given
-  // element type.
-  tree
-  slice_type_tree(tree element_type_tree);
-
-  // Given a tree for a slice type, return the tree for the element
-  // type.
-  static tree
-  slice_element_type_tree(tree slice_type_tree);
-
   // Build a constructor for a slice.  SLICE_TYPE_TREE is the type of
   // the slice.  VALUES points to the values.  COUNT is the size,
   // CAPACITY is the capacity.  If CAPACITY is NULL, it is set to
@@ -479,27 +553,6 @@ class Gogo
   slice_constructor(tree slice_type_tree, tree values, tree count,
                    tree capacity);
 
-  // Build a constructor for an empty slice.  SLICE_TYPE_TREE is the
-  // type of the slice.
-  static tree
-  empty_slice_constructor(tree slice_type_tree);
-
-  // Build a map descriptor.
-  tree
-  map_descriptor(Map_type*);
-
-  // Return a tree for the type of a map descriptor.  This is struct
-  // __go_map_descriptor in libgo/runtime/map.h.  This is the same for
-  // all map types.
-  tree
-  map_descriptor_type();
-
-  // Build a type descriptor for TYPE using INITIALIZER as the type
-  // descriptor.  This builds a new decl stored in *PDECL.
-  void
-  build_type_descriptor_decl(const Type*, Expression* initializer,
-                            tree* pdecl);
-
   // Build required interface method tables.
   void
   build_interface_method_tables();
@@ -513,7 +566,7 @@ class Gogo
   // Return a tree which allocate SIZE bytes to hold values of type
   // TYPE.
   tree
-  allocate_memory(Type *type, tree size, source_location);
+  allocate_memory(Type *type, tree size, Location);
 
   // Return a type to use for pointer to const char.
   static tree
@@ -530,18 +583,12 @@ class Gogo
 
   // Receive a value from a channel.
   static tree
-  receive_from_channel(tree type_tree, tree channel, bool for_select,
-                      source_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);
-
+  receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel,
+                      Location);
 
   // Make a trampoline which calls FNADDR passing CLOSURE.
   tree
-  make_trampoline(tree fnaddr, tree closure, source_location);
+  make_trampoline(tree fnaddr, tree closure, Location);
 
  private:
   // During parsing, we keep a stack of functions.  Each function on
@@ -558,18 +605,14 @@ class Gogo
   // The stack of functions.
   typedef std::vector<Open_function> Open_functions;
 
-  // Create trees for implicit builtin functions.
-  void
-  define_builtin_function_trees();
-
   // Set up the built-in unsafe package.
   void
-  import_unsafe(const std::string&, bool is_exported, source_location);
+  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, source_location location);
+             const std::string& unique_prefix, Location location);
 
   // Return the current binding contour.
   Bindings*
@@ -578,10 +621,6 @@ class Gogo
   const Bindings*
   current_bindings() const;
 
-  // Return the current block.
-  Block*
-  current_block();
-
   // Get the name of the magic initialization function.
   const std::string&
   get_init_fn_name();
@@ -607,32 +646,6 @@ class Gogo
   tree
   ptr_go_string_constant_tree(const std::string&);
 
-  // Return the name to use for a type descriptor decl for an unnamed
-  // type.
-  std::string
-  unnamed_type_descriptor_decl_name(const Type* type);
-
-  // Return the name to use for a type descriptor decl for a type
-  // named NO, defined in IN_FUNCTION.
-  std::string
-  type_descriptor_decl_name(const Named_object* no,
-                           const Named_object* in_function);
-
-  // Where a type descriptor should be defined.
-  enum Type_descriptor_location
-    {
-      // Defined in this file.
-      TYPE_DESCRIPTOR_DEFINED,
-      // Defined in some other file.
-      TYPE_DESCRIPTOR_UNDEFINED,
-      // Common definition which may occur in multiple files.
-      TYPE_DESCRIPTOR_COMMON
-    };
-
-  // Return where the decl for TYPE should be defined.
-  Type_descriptor_location
-  type_descriptor_location(const Type* type);
-
   // Return the type of a trampoline.
   static tree
   trampoline_type_tree();
@@ -643,19 +656,35 @@ class Gogo
   // 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;
-
-  // Hash table mapping map types to map descriptor decls.
-  typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
-                            Type_identical) Map_descriptors;
+  // 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;
 
-  // Map unnamed types to type descriptor decls.
-  typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
-                            Type_identical) Type_descriptor_decls;
+  // 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_;
+  // The object used to keep track of file names and line numbers.
+  Linemap* linemap_;
   // The package we are compiling.
   Package* package_;
   // The list of currently open functions during parsing.
@@ -670,12 +699,12 @@ class Gogo
   // Mapping from package names we have seen to packages.  This does
   // not include the package we are compiling.
   Packages packages_;
-  // Mapping from map types to map descriptors.
-  Map_descriptors* map_descriptors_;
-  // Mapping from unnamed types to type descriptor decls.
-  Type_descriptor_decls* type_descriptor_decls_;
   // 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.
@@ -686,8 +715,14 @@ class Gogo
   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_;
 };
@@ -697,7 +732,7 @@ class Gogo
 class Block
 {
  public:
-  Block(Block* enclosing, source_location);
+  Block(Block* enclosing, Location);
 
   // Return the enclosing block.
   const Block*
@@ -720,13 +755,13 @@ class Block
 
   // Return the start location.  This is normally the location of the
   // left curly brace which starts the block.
-  source_location
+  Location
   start_location() const
   { return this->start_location_; }
 
   // Return the end location.  This is normally the location of the
   // right curly brace which ends the block.
-  source_location
+  Location
   end_location() const
   { return this->end_location_; }
 
@@ -752,7 +787,7 @@ class Block
 
   // Set the end location of the block.
   void
-  set_end_location(source_location location)
+  set_end_location(Location location)
   { this->end_location_ = location; }
 
   // Traverse the tree.
@@ -792,9 +827,9 @@ class Block
   // Binding contour.
   Bindings* bindings_;
   // Location of start of block.
-  source_location start_location_;
+  Location start_location_;
   // Location of end of block.
-  source_location end_location_;
+  Location end_location_;
 };
 
 // A function.
@@ -802,7 +837,7 @@ class Block
 class Function
 {
  public:
-  Function(Function_type* type, Function*, Block*, source_location);
+  Function(Function_type* type, Function*, Block*, Location);
 
   // Return the function's type.
   Function_type*
@@ -847,7 +882,7 @@ class Function
 
   // Add a new field to the closure variable.
   void
-  add_closure_field(Named_object* var, source_location loc)
+  add_closure_field(Named_object* var, Location loc)
   { this->closure_fields_.push_back(std::make_pair(var, loc)); }
 
   // Whether this function needs a closure.
@@ -888,7 +923,7 @@ class Function
   { return this->block_; }
 
   // Get the location of the start of the function.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -898,11 +933,14 @@ class Function
 
   // Add a label definition to the function.
   Label*
-  add_label_definition(const std::string& label_name, source_location);
+  add_label_definition(Gogo*, const std::string& label_name, Location);
 
-  // Add a label reference to a function.
+  // Add a label reference to a function.  ISSUE_GOTO_ERRORS is true
+  // if we should report errors for a goto from the current location
+  // to the label location.
   Label*
-  add_label_reference(const std::string& label_name);
+  add_label_reference(Gogo*, const std::string& label_name,
+                     Location, bool issue_goto_errors);
 
   // Warn about labels that are defined but not used.
   void
@@ -972,11 +1010,11 @@ class Function
   // Get the value to return when not explicitly specified.  May also
   // add statements to execute first to STMT_LIST.
   tree
-  return_value(Gogo*, Named_object*, source_location, tree* stmt_list) const;
+  return_value(Gogo*, Named_object*, Location, tree* stmt_list) const;
 
   // Get a tree for the variable holding the defer stack.
   Expression*
-  defer_stack(source_location);
+  defer_stack(Location);
 
   // Export the function.
   void
@@ -1007,7 +1045,7 @@ class Function
   build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
 
   typedef std::vector<std::pair<Named_object*,
-                               source_location> > Closure_fields;
+                               Location> > Closure_fields;
 
   // The function's type.
   Function_type* type_;
@@ -1026,7 +1064,7 @@ class Function
   // The outer block of statements in the function.
   Block* block_;
   // The source location of the start of the function.
-  source_location location_;
+  Location location_;
   // Labels defined or referenced in the function.
   Labels labels_;
   // The function decl.
@@ -1045,12 +1083,46 @@ class Function
   bool has_recover_thunk_;
 };
 
+// A snapshot of the current binding state.
+
+class Bindings_snapshot
+{
+ public:
+  Bindings_snapshot(const Block*, Location);
+
+  // Report any errors appropriate for a goto from the current binding
+  // state of B to this one.
+  void
+  check_goto_from(const Block* b, Location);
+
+  // Report any errors appropriate for a goto from this binding state
+  // to the current state of B.
+  void
+  check_goto_to(const Block* b);
+
+ private:
+  bool
+  check_goto_block(Location, const Block*, const Block*, size_t*);
+
+  void
+  check_goto_defs(Location, const Block*, size_t, size_t);
+
+  // The current block.
+  const Block* block_;
+  // The number of names currently defined in each open block.
+  // Element 0 is this->block_, element 1 is
+  // this->block_->enclosing(), etc.
+  std::vector<size_t> counts_;
+  // The location where this snapshot was taken.
+  Location location_;
+};
+
 // A function declaration.
 
 class Function_declaration
 {
  public:
-  Function_declaration(Function_type* fntype, source_location location)
+  Function_declaration(Function_type* fntype, Location location)
     : fntype_(fntype), location_(location), asm_name_(), fndecl_(NULL)
   { }
 
@@ -1058,7 +1130,7 @@ class Function_declaration
   type() const
   { return this->fntype_; }
 
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1084,7 +1156,7 @@ class Function_declaration
   // The type of the function.
   Function_type* fntype_;
   // The location of the declaration.
-  source_location location_;
+  Location location_;
   // The assembler name: this is the name to use in references to the
   // function.  This is normally empty.
   std::string asm_name_;
@@ -1098,7 +1170,7 @@ class Variable
 {
  public:
   Variable(Type*, Expression*, bool is_global, bool is_parameter,
-          bool is_receiver, source_location);
+          bool is_receiver, Location);
 
   // Get the type of the variable.
   Type*
@@ -1109,8 +1181,7 @@ class Variable
 
   // Return whether the type is defined yet.
   bool
-  has_type() const
-  { return this->type_ != NULL; }
+  has_type() const;
 
   // Get the initial value.
   Expression*
@@ -1175,8 +1246,24 @@ class Variable
   is_in_heap() const
   { return this->is_address_taken_ && !this->is_global_; }
 
+  // Note that something takes the address of this variable.
+  void
+  set_address_taken()
+  { this->is_address_taken_ = true; }
+
+  // Return whether the address is taken but does not escape.
+  bool
+  is_non_escaping_address_taken() const
+  { return this->is_non_escaping_address_taken_; }
+
+  // Note that something takes the address of this variable such that
+  // the address does not escape the function.
+  void
+  set_non_escaping_address_taken()
+  { this->is_non_escaping_address_taken_ = true; }
+
   // Get the source location of the variable's declaration.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1188,6 +1275,16 @@ class Variable
     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()
@@ -1210,7 +1307,7 @@ class Variable
 
   // Lower the initialization expression after parsing is complete.
   void
-  lower_init_expression(Gogo*, Named_object*);
+  lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
 
   // A special case: the init value is used only to determine the
   // type.  This is used if the variable is defined using := with the
@@ -1261,17 +1358,12 @@ class Variable
 
   // Traverse the initializer expression.
   int
-  traverse_expression(Traverse*);
+  traverse_expression(Traverse*, unsigned int traverse_mask);
 
   // Determine the type of the variable if necessary.
   void
   determine_type();
 
-  // Note that something takes the address of this variable.
-  void
-  set_address_taken()
-  { this->is_address_taken_ = true; }
-
   // Get the backend representation of the variable.
   Bvariable*
   get_backend_variable(Gogo*, Named_object*, const Package*,
@@ -1318,7 +1410,7 @@ class Variable
   // Statements to run before the init statement.
   Block* preinit_;
   // Location of variable definition.
-  source_location location_;
+  Location location_;
   // Backend representation.
   Bvariable* backend_;
   // Whether this is a global variable.
@@ -1329,8 +1421,15 @@ class Variable
   bool is_receiver_ : 1;
   // Whether this is the varargs parameter of a function.
   bool is_varargs_parameter_ : 1;
-  // Whether something takes the address of this variable.
+  // 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.
   bool is_address_taken_ : 1;
+  // Whether something takes the address of this variable such that
+  // the address does not escape the function.
+  bool is_non_escaping_address_taken_ : 1;
   // True if we have seen this variable in a traversal.
   bool seen_ : 1;
   // True if we have lowered the initialization expression.
@@ -1356,9 +1455,10 @@ class Result_variable
 {
  public:
   Result_variable(Type* type, Function* function, int index,
-                 source_location location)
+                 Location location)
     : type_(type), function_(function), index_(index), location_(location),
-      backend_(NULL), is_address_taken_(false)
+      backend_(NULL), is_address_taken_(false),
+      is_non_escaping_address_taken_(false)
   { }
 
   // Get the type of the result variable.
@@ -1377,7 +1477,7 @@ class Result_variable
   { return this->index_; }
 
   // The location of the variable definition.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1391,6 +1491,17 @@ class Result_variable
   set_address_taken()
   { this->is_address_taken_ = true; }
 
+  // Return whether the address is taken but does not escape.
+  bool
+  is_non_escaping_address_taken() const
+  { return this->is_non_escaping_address_taken_; }
+
+  // Note that something takes the address of this variable such that
+  // the address does not escape the function.
+  void
+  set_non_escaping_address_taken()
+  { this->is_non_escaping_address_taken_ = true; }
+
   // Whether this variable should live in the heap.
   bool
   is_in_heap() const
@@ -1414,11 +1525,14 @@ class Result_variable
   // Index in list of results.
   int index_;
   // Where the result variable is defined.
-  source_location location_;
+  Location location_;
   // Backend representation.
   Bvariable* backend_;
   // Whether something takes the address of this variable.
   bool is_address_taken_;
+  // Whether something takes the address of this variable such that
+  // the address does not escape the function.
+  bool is_non_escaping_address_taken_;
 };
 
 // The value we keep for a named constant.  This lets us hold a type
@@ -1428,7 +1542,7 @@ class Named_constant
 {
  public:
   Named_constant(Type* type, Expression* expr, int iota_value,
-                source_location location)
+                Location location)
     : type_(type), expr_(expr), iota_value_(iota_value), location_(location),
       lowering_(false)
   { }
@@ -1445,7 +1559,7 @@ class Named_constant
   iota_value() const
   { return this->iota_value_; }
 
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1496,7 +1610,7 @@ class Named_constant
   // we lower.
   int iota_value_;
   // The location of the definition.
-  source_location location_;
+  Location location_;
   // Whether we are currently lowering this constant.
   bool lowering_;
 };
@@ -1506,13 +1620,13 @@ class Named_constant
 class Type_declaration
 {
  public:
-  Type_declaration(source_location location)
+  Type_declaration(Location location)
     : location_(location), in_function_(NULL), methods_(),
       issued_warning_(false)
   { }
 
   // Return the location.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1534,8 +1648,8 @@ class Type_declaration
 
   // Add a method declaration to this type.
   Named_object*
-  add_method_declaration(const std::string& name, Function_type* type,
-                        source_location location);
+  add_method_declaration(const std::string& name, Package*,
+                        Function_type* type, Location location);
 
   // Return whether any methods were defined.
   bool
@@ -1554,7 +1668,7 @@ class Type_declaration
   typedef std::vector<Named_object*> Methods;
 
   // The location of the type declaration.
-  source_location location_;
+  Location location_;
   // If this type is declared in a function, a pointer back to the
   // function in which it is defined.
   Named_object* in_function_;
@@ -1574,12 +1688,12 @@ class Type_declaration
 class Unknown_name
 {
  public:
-  Unknown_name(source_location location)
+  Unknown_name(Location location)
     : location_(location), real_named_object_(NULL)
   { }
 
   // Return the location where this name was first seen.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -1595,7 +1709,7 @@ class Unknown_name
 
  private:
   // The location where this name was first seen.
-  source_location location_;
+  Location location_;
   // The real named object when it is known.
   Named_object*
   real_named_object_;
@@ -1612,6 +1726,9 @@ class Named_object
   {
     // 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.
@@ -1644,6 +1761,10 @@ class Named_object
   // Classifiers.
 
   bool
+  is_erroneous() const
+  { return this->classification_ == NAMED_OBJECT_ERRONEOUS; }
+
+  bool
   is_unknown() const
   { return this->classification_ == NAMED_OBJECT_UNKNOWN; }
 
@@ -1686,17 +1807,21 @@ class Named_object
   // Creators.
 
   static Named_object*
-  make_unknown_name(const std::string& name, source_location);
+  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*
   make_constant(const Typed_identifier&, const Package*, Expression*,
                int iota_value);
 
   static Named_object*
-  make_type(const std::string&, const Package*, Type*, source_location);
+  make_type(const std::string&, const Package*, Type*, Location);
 
   static Named_object*
-  make_type_declaration(const std::string&, const Package*, source_location);
+  make_type_declaration(const std::string&, const Package*, Location);
 
   static Named_object*
   make_variable(const std::string&, const Package*, Variable*);
@@ -1712,7 +1837,7 @@ class Named_object
 
   static Named_object*
   make_function_declaration(const std::string&, const Package*, Function_type*,
-                           source_location);
+                           Location);
 
   static Named_object*
   make_package(const std::string& alias, Package* package);
@@ -1888,7 +2013,7 @@ class Named_object
   }
 
   // The location where this object was defined or referenced.
-  source_location
+  Location
   location() const;
 
   // Convert a variable to the backend representation.
@@ -1956,9 +2081,14 @@ class Bindings
 
   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, source_location location)
+  add_unknown_name(const std::string& name, Location location)
   {
     return this->add_named_object(Named_object::make_unknown_name(name,
                                                                  location));
@@ -1977,7 +2107,7 @@ class Bindings
   // Add a type.
   Named_object*
   add_type(const std::string& name, const Package* package, Type* type,
-          source_location location)
+          Location location)
   {
     return this->add_named_object(Named_object::make_type(name, package, type,
                                                          location));
@@ -1991,7 +2121,7 @@ class Bindings
   // Add a type declaration.
   Named_object*
   add_type_declaration(const std::string& name, const Package* package,
-                      source_location location)
+                      Location location)
   {
     Named_object* no = Named_object::make_type_declaration(name, package,
                                                           location);
@@ -2022,7 +2152,7 @@ class Bindings
   // Add a function declaration.
   Named_object*
   add_function_declaration(const std::string& name, const Package* package,
-                          Function_type* type, source_location location);
+                          Function_type* type, Location location);
 
   // Add a package.  The location is the location of the import
   // statement.
@@ -2065,6 +2195,11 @@ class Bindings
   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);
@@ -2142,7 +2277,8 @@ class Label
 {
  public:
   Label(const std::string& name)
-    : name_(name), location_(0), is_used_(false), blabel_(NULL)
+    : name_(name), location_(Linemap::unknown_location()), snapshot_(NULL),
+      refs_(), is_used_(false), blabel_(NULL)
   { }
 
   // Return the label's name.
@@ -2153,7 +2289,7 @@ class Label
   // Return whether the label has been defined.
   bool
   is_defined() const
-  { return this->location_ != 0; }
+  { return !Linemap::is_unknown_location(this->location_); }
 
   // Return whether the label has been used.
   bool
@@ -2166,16 +2302,41 @@ class Label
   { this->is_used_ = true; }
 
   // Return the location of the definition.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
-  // Define the label at LOCATION.
+  // Return the bindings snapshot.
+  Bindings_snapshot*
+  snapshot() const
+  { return this->snapshot_; }
+
+  // Add a snapshot of a goto which refers to this label.
+  void
+  add_snapshot_ref(Bindings_snapshot* snapshot)
+  {
+    go_assert(Linemap::is_unknown_location(this->location_));
+    this->refs_.push_back(snapshot);
+  }
+
+  // Return the list of snapshots of goto statements which refer to
+  // this label.
+  const std::vector<Bindings_snapshot*>&
+  refs() const
+  { return this->refs_; }
+
+  // Clear the references.
+  void
+  clear_refs();
+
+  // Define the label at LOCATION with the given bindings snapshot.
   void
-  define(source_location location)
+  define(Location location, Bindings_snapshot* snapshot)
   {
-    go_assert(this->location_ == 0);
+    go_assert(Linemap::is_unknown_location(this->location_)
+              && this->snapshot_ == NULL);
     this->location_ = location;
+    this->snapshot_ = snapshot;
   }
 
   // Return the backend representation for this label.
@@ -2186,14 +2347,19 @@ class Label
   // to get the return address of a deferred function to see whether
   // the function may call recover.
   Bexpression*
-  get_addr(Translate_context*, source_location location);
+  get_addr(Translate_context*, Location location);
 
  private:
   // The name of the label.
   std::string name_;
   // The location of the definition.  This is 0 if the label has not
   // yet been defined.
-  source_location location_;
+  Location location_;
+  // A snapshot of the set of bindings defined at this label, used to
+  // issue errors about invalid goto statements.
+  Bindings_snapshot* snapshot_;
+  // A list of snapshots of goto statements which refer to this label.
+  std::vector<Bindings_snapshot*> refs_;
   // Whether the label has been used.
   bool is_used_;
   // The backend representation.
@@ -2205,18 +2371,18 @@ class Label
 class Unnamed_label
 {
  public:
-  Unnamed_label(source_location location)
+  Unnamed_label(Location location)
     : location_(location), blabel_(NULL)
   { }
 
   // Get the location where the label is defined.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
   // Set the location where the label is defined.
   void
-  set_location(source_location location)
+  set_location(Location location)
   { this->location_ = location; }
 
   // Return a statement which defines this label.
@@ -2225,7 +2391,7 @@ class Unnamed_label
 
   // Return a goto to this label from LOCATION.
   Bstatement*
-  get_goto(Translate_context*, source_location location);
+  get_goto(Translate_context*, Location location);
 
  private:
   // Return the backend representation.
@@ -2233,7 +2399,7 @@ class Unnamed_label
   get_blabel(Translate_context*);
 
   // The location where the label is defined.
-  source_location location_;
+  Location location_;
   // The backend representation of this label.
   Blabel* blabel_;
 };
@@ -2244,7 +2410,7 @@ class Package
 {
  public:
   Package(const std::string& name, const std::string& unique_prefix,
-         source_location location);
+         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
@@ -2254,7 +2420,7 @@ class Package
   { return this->name_; }
 
   // Return the location of the import statement.
-  source_location
+  Location
   location() const
   { return this->location_; }
 
@@ -2337,7 +2503,7 @@ class Package
   // Set the location of the package.  This is used if it is seen in a
   // different import before it is really imported.
   void
-  set_location(source_location location)
+  set_location(Location location)
   { this->location_ = location; }
 
   // Add a constant to the package.
@@ -2347,12 +2513,12 @@ class Package
 
   // Add a type to the package.
   Named_object*
-  add_type(const std::string& name, Type* type, source_location location)
+  add_type(const std::string& name, Type* type, Location location)
   { return this->bindings_->add_type(name, this, type, location); }
 
   // Add a type declaration to the package.
   Named_object*
-  add_type_declaration(const std::string& name, source_location location)
+  add_type_declaration(const std::string& name, Location location)
   { return this->bindings_->add_type_declaration(name, this, location); }
 
   // Add a variable to the package.
@@ -2363,7 +2529,7 @@ class Package
   // Add a function declaration to the package.
   Named_object*
   add_function_declaration(const std::string& name, Function_type* type,
-                          source_location loc)
+                          Location loc)
   { return this->bindings_->add_function_declaration(name, this, type, loc); }
 
   // Determine types of constants.
@@ -2382,7 +2548,7 @@ class Package
   // is used to run init functions in the right order.
   int priority_;
   // The location of the import statement.
-  source_location location_;
+  Location location_;
   // True if some name from this package was used.  This is mutable
   // because we can use a package even if we have a const pointer to
   // it.
@@ -2488,8 +2654,13 @@ class Traverse
   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;
 
@@ -2501,6 +2672,46 @@ class Traverse
   Expressions_seen* expressions_seen_;
 };
 
+// A class which makes it easier to insert new statements before the
+// current statement during a traversal.
+
+class Statement_inserter
+{
+ public:
+  // Empty constructor.
+  Statement_inserter()
+    : block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL)
+  { }
+
+  // Constructor for a statement in a block.
+  Statement_inserter(Block* block, size_t *pindex)
+    : block_(block), pindex_(pindex), gogo_(NULL), var_(NULL)
+  { }
+
+  // Constructor for a global variable.
+  Statement_inserter(Gogo* gogo, Variable* var)
+    : block_(NULL), pindex_(NULL), gogo_(gogo), var_(var)
+  { go_assert(var->is_global()); }
+
+  // We use the default copy constructor and assignment operator.
+
+  // Insert S before the statement we are traversing, or before the
+  // initialization expression of a global variable.
+  void
+  insert(Statement* s);
+
+ private:
+  // The block that the statement is in.
+  Block* block_;
+  // The index of the statement that we are traversing.
+  size_t* pindex_;
+  // The IR, needed when looking at an initializer expression for a
+  // global variable.
+  Gogo* gogo_;
+  // The global variable, when looking at an initializer expression.
+  Variable* var_;
+};
+
 // When translating the gogo IR into the backend data structure, this
 // is the context we pass down the blocks and statements.
 
@@ -2602,6 +2813,9 @@ static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8;
 // 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();