diff mbox

Go patch committed: Updated 4.8 branch

Message ID mcr38o1azvw.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 16, 2013, 5:28 p.m. UTC
I committed this patch to the 4.8 branch to bring in the last set of Go
1.1.2 bug fixes and patches.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.

Ian


2013-10-16  Ian Lance Taylor  <iant@google.com>

	Bring in from mainline:

	2013-10-11  Chris Manghane  <cmang@google.com>
	* go-gcc.cc (Gcc_backend::function_code_expression): New
	function.

	2013-10-10  Chris Manghane  <cmang@google.com>
	* go-gcc.cc (Backend::error_function): New function.
	(Backend::function): New function.
	(Backend::make_function): New function.
	(function_to_tree): New function.
diff mbox

Patch

Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 203707)
+++ libgo/Makefile.am	(working copy)
@@ -424,6 +424,7 @@  runtime_files = \
 	runtime/go-caller.c \
 	runtime/go-callers.c \
 	runtime/go-can-convert-interface.c \
+	runtime/go-cdiv.c \
 	runtime/go-cgo.c \
 	runtime/go-check-interface.c \
 	runtime/go-construct-map.c \
Index: libgo/runtime/go-signal.c
===================================================================
--- libgo/runtime/go-signal.c	(revision 203707)
+++ libgo/runtime/go-signal.c	(working copy)
@@ -399,6 +399,9 @@  sig_tramp_info (int sig, Siginfo *info,
 {
   G *gp;
   M *mp;
+#ifdef USING_SPLIT_STACK
+  void *stack_context[10];
+#endif
 
   /* We are now running on the stack registered via sigaltstack.
      (Actually there is a small span of time between runtime_siginit
@@ -409,7 +412,7 @@  sig_tramp_info (int sig, Siginfo *info,
   if (gp != NULL)
     {
 #ifdef USING_SPLIT_STACK
-      __splitstack_getcontext (&gp->stack_context[0]);
+      __splitstack_getcontext (&stack_context[0]);
 #endif
     }
 
@@ -432,7 +435,7 @@  sig_tramp_info (int sig, Siginfo *info,
   if (gp != NULL)
     {
 #ifdef USING_SPLIT_STACK
-      __splitstack_setcontext (&gp->stack_context[0]);
+      __splitstack_setcontext (&stack_context[0]);
 #endif
     }
 }
Index: libgo/runtime/go-cdiv.c
===================================================================
--- libgo/runtime/go-cdiv.c	(revision 0)
+++ libgo/runtime/go-cdiv.c	(revision 0)
@@ -0,0 +1,46 @@ 
+/* go-cdiv.c -- complex division routines
+
+   Copyright 2013 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* Calls to these functions are generated by the Go frontend for
+   division of complex64 or complex128.  We use these because Go's
+   complex division expects slightly different results from the GCC
+   default.  When dividing NaN+1.0i / 0+0i, Go expects NaN+NaNi but
+   GCC generates NaN+Infi.  NaN+Infi seems wrong seems the rules of
+   C99 Annex G specify that if either side of a complex number is Inf,
+   the the whole number is Inf, but an operation involving NaN ought
+   to result in NaN, not Inf.  */
+
+__complex float
+__go_complex64_div (__complex float a, __complex float b)
+{
+  if (__builtin_expect (b == 0+0i, 0))
+    {
+      if (!__builtin_isinff (__real__ a)
+	  && !__builtin_isinff (__imag__ a)
+	  && (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a)))
+	{
+	  /* Pass "1" to nanf to match math/bits.go.  */
+	  return __builtin_nanf("1") + __builtin_nanf("1")*1i;
+	}
+    }
+  return a / b;
+}
+
+__complex double
+__go_complex128_div (__complex double a, __complex double b)
+{
+  if (__builtin_expect (b == 0+0i, 0))
+    {
+      if (!__builtin_isinf (__real__ a)
+	  && !__builtin_isinf (__imag__ a)
+	  && (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a)))
+	{
+	  /* Pass "1" to nan to match math/bits.go.  */
+	  return __builtin_nan("1") + __builtin_nan("1")*1i;
+	}
+    }
+  return a / b;
+}
Index: libgo/runtime/go-make-slice.c
===================================================================
--- libgo/runtime/go-make-slice.c	(revision 203707)
+++ libgo/runtime/go-make-slice.c	(working copy)
@@ -34,7 +34,10 @@  __go_make_slice2 (const struct __go_type
   std = (const struct __go_slice_type *) td;
 
   ilen = (intgo) len;
-  if (ilen < 0 || (uintptr_t) ilen != len)
+  if (ilen < 0
+      || (uintptr_t) ilen != len
+      || (std->__element_type->__size > 0
+	  && len > MaxMem / std->__element_type->__size))
     runtime_panicstring ("makeslice: len out of range");
 
   icap = (intgo) cap;
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 203707)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -232,6 +232,9 @@  class Gcc_backend : public Backend
   Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location);
 
+  Bexpression*
+  function_code_expression(Bfunction*, Location);
+
   // Statements.
 
   Bstatement*
@@ -334,6 +337,17 @@  class Gcc_backend : public Backend
   Bexpression*
   label_address(Blabel*, Location);
 
+  // Functions.
+
+  Bfunction*
+  error_function()
+  { return this->make_function(error_mark_node); }
+
+  Bfunction*
+  function(Btype* fntype, const std::string& name, const std::string& asm_name,
+           bool is_visible, bool is_declaration, bool is_inlinable,
+           bool disable_split_stack, bool in_unique_section, Location);
+
  private:
   // Make a Bexpression from a tree.
   Bexpression*
@@ -350,6 +364,10 @@  class Gcc_backend : public Backend
   make_type(tree t)
   { return new Btype(t); }
 
+  Bfunction*
+  make_function(tree t)
+  { return new Bfunction(t); }
+
   Btype*
   fill_in_struct(Btype*, const std::vector<Btyped_identifier>&);
 
@@ -966,6 +984,19 @@  Gcc_backend::convert_expression(Btype* t
   return tree_to_expr(ret);
 }
 
+// Get the address of a function.
+
+Bexpression*
+Gcc_backend::function_code_expression(Bfunction* bfunc, Location location)
+{
+  tree func = bfunc->get_tree();
+  if (func == error_mark_node)
+    return this->error_expression();
+
+  tree ret = build_fold_addr_expr_loc(location.gcc_location(), func);
+  return this->make_expression(ret);
+}
+
 // An expression as a statement.
 
 Bstatement*
@@ -1724,6 +1755,56 @@  Gcc_backend::label_address(Blabel* label
   return this->make_expression(ret);
 }
 
+// Declare or define a new function.
+
+Bfunction*
+Gcc_backend::function(Btype* fntype, const std::string& name,
+                      const std::string& asm_name, bool is_visible,
+                      bool is_declaration, bool is_inlinable,
+                      bool disable_split_stack, bool in_unique_section,
+                      Location location)
+{
+  tree functype = fntype->get_tree();
+  if (functype != error_mark_node)
+    {
+      gcc_assert(FUNCTION_POINTER_TYPE_P(functype));
+      functype = TREE_TYPE(functype);
+    }
+  tree id = get_identifier_from_string(name);
+  if (functype == error_mark_node || id == error_mark_node)
+    return this->error_function();
+
+  tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
+  if (!asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+  if (is_visible)
+    TREE_PUBLIC(decl) = 1;
+  if (is_declaration)
+    DECL_EXTERNAL(decl) = 1;
+  else
+    {
+      tree restype = TREE_TYPE(functype);
+      tree resdecl =
+          build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype);
+      DECL_ARTIFICIAL(resdecl) = 1;
+      DECL_IGNORED_P(resdecl) = 1;
+      DECL_CONTEXT(resdecl) = decl;
+      DECL_RESULT(decl) = resdecl;
+    }
+  if (!is_inlinable)
+    DECL_UNINLINABLE(decl) = 1;
+  if (disable_split_stack)
+    {
+      tree attr = get_identifier("__no_split_stack__");
+      DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
+    }
+  if (in_unique_section)
+    resolve_unique_section(decl, 0, 1);
+
+  go_preserve_from_gc(decl);
+  return new Bfunction(decl);
+}
+
 // The single backend.
 
 static Gcc_backend gcc_backend;
@@ -1799,3 +1880,9 @@  var_to_tree(Bvariable* bv)
 {
   return bv->get_tree();
 }
+
+tree
+function_to_tree(Bfunction* bf)
+{
+  return bf->get_tree();
+}
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 203707)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -1219,7 +1219,7 @@  Func_expression::do_type()
 
 // Get the tree for the code of a function expression.
 
-tree
+Bexpression*
 Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
 {
   Function_type* fntype;
@@ -1237,25 +1237,18 @@  Func_expression::get_code_pointer(Gogo*
       error_at(loc,
 	       "invalid use of special builtin function %qs; must be called",
 	       no->message_name().c_str());
-      return error_mark_node;
+      return gogo->backend()->error_expression();
     }
 
-  tree id = no->get_id(gogo);
-  if (id == error_mark_node)
-    return error_mark_node;
-
-  tree fndecl;
+  Bfunction* fndecl;
   if (no->is_function())
-    fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
+    fndecl = no->func_value()->get_or_make_decl(gogo, no);
   else if (no->is_function_declaration())
-    fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id);
+    fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no);
   else
     go_unreachable();
 
-  if (fndecl == error_mark_node)
-    return error_mark_node;
-
-  return build_fold_addr_expr_loc(loc.gcc_location(), fndecl);
+  return gogo->backend()->function_code_expression(fndecl, loc);
 }
 
 // Get the tree for a function expression.  This is used when we take
@@ -1492,8 +1485,10 @@  class Func_code_reference_expression : p
 tree
 Func_code_reference_expression::do_get_tree(Translate_context* context)
 {
-  return Func_expression::get_code_pointer(context->gogo(), this->function_,
-					   this->location());
+  Bexpression* ret =
+      Func_expression::get_code_pointer(context->gogo(), this->function_,
+                                        this->location());
+  return expr_to_tree(ret);
 }
 
 // Make a reference to the code of a function.
@@ -3055,8 +3050,7 @@  class Type_conversion_expression : publi
   do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
   bool
-  do_is_constant() const
-  { return this->expr_->is_constant(); }
+  do_is_constant() const;
 
   bool
   do_numeric_constant_value(Numeric_constant*) const;
@@ -3198,6 +3192,27 @@  Type_conversion_expression::do_lower(Gog
   return this;
 }
 
+// Return whether a type conversion is a constant.
+
+bool
+Type_conversion_expression::do_is_constant() const
+{
+  if (!this->expr_->is_constant())
+    return false;
+
+  // A conversion to a type that may not be used as a constant is not
+  // a constant.  For example, []byte(nil).
+  Type* type = this->type_;
+  if (type->integer_type() == NULL
+      && type->float_type() == NULL
+      && type->complex_type() == NULL
+      && !type->is_boolean_type()
+      && !type->is_string_type())
+    return false;
+
+  return true;
+}
+
 // Return the constant numeric value if there is one.
 
 bool
@@ -5586,6 +5601,15 @@  Binary_expression::do_determine_type(con
       subcontext.type = NULL;
     }
 
+  if (this->op_ == OPERATOR_ANDAND || this->op_ == OPERATOR_OROR)
+    {
+      // For a logical operation, the context does not determine the
+      // types of the operands.  The operands must be some boolean
+      // type but if the context has a boolean type they do not
+      // inherit it.  See http://golang.org/issue/3924.
+      subcontext.type = NULL;
+    }
+
   // Set the context for the left hand operand.
   if (is_shift_op)
     {
@@ -5967,6 +5991,43 @@  Binary_expression::do_get_tree(Translate
 				right);
     }
 
+  // For complex division Go wants slightly different results than the
+  // GCC library provides, so we have our own runtime routine.
+  if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
+    {
+      const char *name;
+      tree *pdecl;
+      Type* ctype;
+      static tree complex64_div_decl;
+      static tree complex128_div_decl;
+      switch (this->left_->type()->complex_type()->bits())
+	{
+	case 64:
+	  name = "__go_complex64_div";
+	  pdecl = &complex64_div_decl;
+	  ctype = Type::lookup_complex_type("complex64");
+	  break;
+	case 128:
+	  name = "__go_complex128_div";
+	  pdecl = &complex128_div_decl;
+	  ctype = Type::lookup_complex_type("complex128");
+	  break;
+	default:
+	  go_unreachable();
+	}
+      Btype* cbtype = ctype->get_backend(gogo);
+      tree ctype_tree = type_to_tree(cbtype);
+      return Gogo::call_builtin(pdecl,
+				this->location(),
+				name,
+				2,
+				ctype_tree,
+				ctype_tree,
+				fold_convert_loc(gccloc, ctype_tree, left),
+				type,
+				fold_convert_loc(gccloc, ctype_tree, right));
+    }
+
   tree compute_type = excess_precision_type(type);
   if (compute_type != NULL_TREE)
     {
@@ -7191,6 +7252,15 @@  Builtin_call_expression::do_lower(Gogo*
   if (this->code_ == BUILTIN_OFFSETOF)
     {
       Expression* arg = this->one_arg();
+
+      if (arg->bound_method_expression() != NULL
+	  || arg->interface_field_reference_expression() != NULL)
+	{
+	  this->report_error(_("invalid use of method value as argument "
+			       "of Offsetof"));
+	  return this;
+	}
+
       Field_reference_expression* farg = arg->field_reference_expression();
       while (farg != NULL)
 	{
@@ -7200,7 +7270,8 @@  Builtin_call_expression::do_lower(Gogo*
 	  // it must not be reached through pointer indirections.
 	  if (farg->expr()->deref() != farg->expr())
 	    {
-	      this->report_error(_("argument of Offsetof implies indirection of an embedded field"));
+	      this->report_error(_("argument of Offsetof implies "
+				   "indirection of an embedded field"));
 	      return this;
 	    }
 	  // Go up until we reach the original base.
@@ -7476,7 +7547,7 @@  Builtin_call_expression::check_int_value
       switch (nc.to_unsigned_long(&v))
 	{
 	case Numeric_constant::NC_UL_VALID:
-	  return true;
+	  break;
 	case Numeric_constant::NC_UL_NOTINT:
 	  error_at(e->location(), "non-integer %s argument to make",
 		   is_length ? "len" : "cap");
@@ -7488,8 +7559,23 @@  Builtin_call_expression::check_int_value
 	case Numeric_constant::NC_UL_BIG:
 	  // We don't want to give a compile-time error for a 64-bit
 	  // value on a 32-bit target.
-	  return true;
+	  break;
 	}
+
+      mpz_t val;
+      if (!nc.to_int(&val))
+	go_unreachable();
+      int bits = mpz_sizeinbase(val, 2);
+      mpz_clear(val);
+      Type* int_type = Type::lookup_integer_type("int");
+      if (bits >= int_type->integer_type()->bits())
+	{
+	  error_at(e->location(), "%s argument too large for make",
+		   is_length ? "len" : "cap");
+	  return false;
+	}
+
+      return true;
     }
 
   if (e->type()->integer_type() != NULL)
@@ -7595,6 +7681,8 @@  Find_call_expression::expression(Express
 bool
 Builtin_call_expression::do_is_constant() const
 {
+  if (this->is_error_expression())
+    return true;
   switch (this->code_)
     {
     case BUILTIN_LEN:
@@ -9744,14 +9832,8 @@  Call_expression::do_get_tree(Translate_c
     }
 
   tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
-  if (fntype_tree == error_mark_node)
-    return error_mark_node;
-  go_assert(POINTER_TYPE_P(fntype_tree));
-  if (TREE_TYPE(fntype_tree) == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(TREE_TYPE(fntype_tree)) == RECORD_TYPE);
-  tree fnfield_type = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(fntype_tree)));
-  if (fnfield_type == error_mark_node)
+  tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
+  if (fntype_tree == error_mark_node || fnfield_type == error_mark_node)
     return error_mark_node;
   go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
   tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
@@ -9763,7 +9845,7 @@  Call_expression::do_get_tree(Translate_c
   if (func != NULL)
     {
       Named_object* no = func->named_object();
-      fn = Func_expression::get_code_pointer(gogo, no, location);
+      fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
       if (!has_closure)
 	closure_tree = NULL_TREE;
       else
@@ -10817,11 +10899,20 @@  String_index_expression::do_determine_ty
 void
 String_index_expression::do_check_types(Gogo*)
 {
-  if (this->start_->type()->integer_type() == NULL)
+  Numeric_constant nc;
+  unsigned long v;
+  if (this->start_->type()->integer_type() == NULL
+      && !this->start_->type()->is_error()
+      && (!this->start_->numeric_constant_value(&nc)
+	  || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
     this->report_error(_("index must be integer"));
   if (this->end_ != NULL
       && this->end_->type()->integer_type() == NULL
-      && !this->end_->is_nil_expression())
+      && !this->end_->type()->is_error()
+      && !this->end_->is_nil_expression()
+      && !this->end_->is_error_expression()
+      && (!this->end_->numeric_constant_value(&nc)
+	  || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
     this->report_error(_("slice end must be integer"));
 
   std::string sval;
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 203707)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -1514,8 +1514,8 @@  class Func_expression : public Expressio
   closure()
   { return this->closure_; }
 
-  // Return a tree for the code for a function.
-  static tree
+  // Return a backend expression for the code of a function.
+  static Bexpression*
   get_code_pointer(Gogo*, Named_object* function, Location loc);
 
  protected:
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 203707)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -23,7 +23,7 @@  class Bexpression;
 // The backend representation of a statement.
 class Bstatement;
 
-// The backend representation of a function definition.
+// The backend representation of a function definition or declaration.
 class Bfunction;
 
 // The backend representation of a block.
@@ -266,6 +266,11 @@  class Backend
   virtual Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location) = 0;
 
+  // Create an expression for the address of a function.  This is used to
+  // get the address of the code for a function.
+  virtual Bexpression*
+  function_code_expression(Bfunction*, Location) = 0;
+
   // Statements.
 
   // Create an error statement.  This is used for cases which should
@@ -498,6 +503,32 @@  class Backend
   // recover.
   virtual Bexpression*
   label_address(Blabel*, Location) = 0;
+
+  // Functions.
+
+  // Create an error function.  This is used for cases which should
+  // not occur in a correct program, in order to keep the compilation
+  // going without crashing.
+  virtual Bfunction*
+  error_function() = 0;
+
+  // Declare or define a function of FNTYPE.
+  // NAME is the Go name of the function. ASM_NAME, if not the empty string, is
+  // the name that should be used in the symbol table; this will be non-empty if
+  // a magic extern comment is used.
+  // IS_VISIBLE is true if this function should be visible outside of the
+  // current compilation unit. IS_DECLARATION is true if this is a function
+  // declaration rather than a definition; the function definition will be in
+  // another compilation unit.
+  // IS_INLINABLE is true if the function can be inlined.
+  // DISABLE_SPLIT_STACK is true if this function may not split the stack; this
+  // is used for the implementation of recover.
+  // IN_UNIQUE_SECTION is true if this function should be put into a unique
+  // location if possible; this is used for field tracking.
+  virtual Bfunction*
+  function(Btype* fntype, const std::string& name, const std::string& asm_name,
+           bool is_visible, bool is_declaration, bool is_inlinable,
+           bool disable_split_stack, bool in_unique_section, Location) = 0;
 };
 
 // The backend interface has to define this function.
@@ -517,5 +548,6 @@  extern tree expr_to_tree(Bexpression*);
 extern tree stat_to_tree(Bstatement*);
 extern tree block_to_tree(Bblock*);
 extern tree var_to_tree(Bvariable*);
+extern tree function_to_tree(Bfunction*);
 
 #endif // !defined(GO_BACKEND_H)
Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 203707)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -48,6 +48,7 @@  class Bstatement;
 class Bblock;
 class Bvariable;
 class Blabel;
+class Bfunction;
 
 // This file declares the basic classes used to hold the internal
 // representation of Go which is built by the parser.
@@ -952,6 +953,15 @@  class Function
     this->nointerface_ = true;
   }
 
+  // Record that this function is a stub method created for an unnamed
+  // type.
+  void
+  set_is_unnamed_type_stub_method()
+  {
+    go_assert(this->is_method());
+    this->is_unnamed_type_stub_method_ = true;
+  }
+
   // Add a new field to the closure variable.
   void
   add_closure_field(Named_object* var, Location loc)
@@ -1089,17 +1099,13 @@  class Function
     this->descriptor_ = descriptor;
   }
 
-  // Return the function's decl given an identifier.
-  tree
-  get_or_make_decl(Gogo*, Named_object*, tree id);
+  // Return the backend representation.
+  Bfunction*
+  get_or_make_decl(Gogo*, Named_object*);
 
   // Return the function's decl after it has been built.
   tree
-  get_decl() const
-  {
-    go_assert(this->fndecl_ != NULL);
-    return this->fndecl_;
-  }
+  get_decl() const;
 
   // Set the function decl to hold a tree of the function code.
   void
@@ -1170,7 +1176,7 @@  class Function
   // The function descriptor, if any.
   Expression* descriptor_;
   // The function decl.
-  tree fndecl_;
+  Bfunction* fndecl_;
   // The defer stack variable.  A pointer to this variable is used to
   // distinguish the defer stack for one function from another.  This
   // is NULL unless we actually need a defer stack.
@@ -1181,6 +1187,9 @@  class Function
   bool results_are_named_ : 1;
   // True if this method should not be included in the type descriptor.
   bool nointerface_ : 1;
+  // True if this function is a stub method created for an unnamed
+  // type.
+  bool is_unnamed_type_stub_method_ : 1;
   // True if this function calls the predeclared recover function.
   bool calls_recover_ : 1;
   // True if this a thunk built for a function which calls recover.
@@ -1265,9 +1274,9 @@  class Function_declaration
   has_descriptor() const
   { return this->descriptor_ != NULL; }
 
-  // Return a decl for the function given an identifier.
-  tree
-  get_or_make_decl(Gogo*, Named_object*, tree id);
+  // Return a backend representation.
+  Bfunction*
+  get_or_make_decl(Gogo*, Named_object*);
 
   // If there is a descriptor, build it into the backend
   // representation.
@@ -1290,7 +1299,7 @@  class Function_declaration
   // The function descriptor, if any.
   Expression* descriptor_;
   // The function decl if needed.
-  tree fndecl_;
+  Bfunction* fndecl_;
 };
 
 // A variable.
@@ -2181,8 +2190,8 @@  class Named_object
   Bvariable*
   get_backend_variable(Gogo*, Named_object* function);
 
-  // Return a tree for the external identifier for this object.
-  tree
+  // Return the external identifier for this object.
+  std::string
   get_id(Gogo*);
 
   // Return a tree representing this object.
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc	(revision 203707)
+++ gcc/go/gofrontend/parse.cc	(working copy)
@@ -744,6 +744,8 @@  Parse::signature(Typed_identifier* recei
     return NULL;
 
   Parse::Names names;
+  if (receiver != NULL)
+    names[receiver->name()] = receiver;
   if (params != NULL)
     this->check_signature_names(params, &names);
   if (results != NULL)
Index: gcc/go/gofrontend/import.h
===================================================================
--- gcc/go/gofrontend/import.h	(revision 203707)
+++ gcc/go/gofrontend/import.h	(working copy)
@@ -149,6 +149,11 @@  class Import
   location() const
   { return this->location_; }
 
+  // Return the package we are importing.
+  Package*
+  package() const
+  { return this->package_; }
+
   // Return the next character.
   int
   peek_char()
Index: gcc/go/gofrontend/runtime.cc
===================================================================
--- gcc/go/gofrontend/runtime.cc	(revision 203707)
+++ gcc/go/gofrontend/runtime.cc	(working copy)
@@ -42,6 +42,8 @@  enum Runtime_function_type
   RFT_RUNE,
   // Go type float64, C type double.
   RFT_FLOAT64,
+  // Go type complex64, C type __complex float.
+  RFT_COMPLEX64,
   // Go type complex128, C type __complex double.
   RFT_COMPLEX128,
   // Go type string, C type struct __go_string.
@@ -126,6 +128,10 @@  runtime_function_type(Runtime_function_t
 	  t = Type::lookup_float_type("float64");
 	  break;
 
+	case RFT_COMPLEX64:
+	  t = Type::lookup_complex_type("complex64");
+	  break;
+
 	case RFT_COMPLEX128:
 	  t = Type::lookup_complex_type("complex128");
 	  break;
@@ -216,6 +222,7 @@  convert_to_runtime_function_type(Runtime
     case RFT_UINTPTR:
     case RFT_RUNE:
     case RFT_FLOAT64:
+    case RFT_COMPLEX64:
     case RFT_COMPLEX128:
     case RFT_STRING:
     case RFT_POINTER:
Index: gcc/go/gofrontend/lex.cc
===================================================================
--- gcc/go/gofrontend/lex.cc	(revision 203707)
+++ gcc/go/gofrontend/lex.cc	(working copy)
@@ -873,7 +873,28 @@  Lex::gather_identifier()
 	      && (cc < 'a' || cc > 'z')
 	      && cc != '_'
 	      && (cc < '0' || cc > '9'))
-	    break;
+	    {
+	      // Check for an invalid character here, as we get better
+	      // error behaviour if we swallow them as part of the
+	      // identifier we are building.
+	      if ((cc >= ' ' && cc < 0x7f)
+		  || cc == '\t'
+		  || cc == '\r'
+		  || cc == '\n')
+		break;
+
+	      this->lineoff_ = p - this->linebuf_;
+	      error_at(this->location(),
+		       "invalid character 0x%x in identifier",
+		       cc);
+	      if (!has_non_ascii_char)
+		{
+		  buf.assign(pstart, p - pstart);
+		  has_non_ascii_char = true;
+		}
+	      if (!Lex::is_invalid_identifier(buf))
+		buf.append("$INVALID$");
+	    }
 	  ++p;
 	  if (is_first)
 	    {
Index: gcc/go/gofrontend/gogo-tree.cc
===================================================================
--- gcc/go/gofrontend/gogo-tree.cc	(revision 203707)
+++ gcc/go/gofrontend/gogo-tree.cc	(working copy)
@@ -985,74 +985,6 @@  Gogo::write_globals()
   delete[] vec;
 }
 
-// Get a tree for the identifier for a named object.
-
-tree
-Named_object::get_id(Gogo* gogo)
-{
-  go_assert(!this->is_variable() && !this->is_result_variable());
-  std::string decl_name;
-  if (this->is_function_declaration()
-      && !this->func_declaration_value()->asm_name().empty())
-    decl_name = this->func_declaration_value()->asm_name();
-  else if (this->is_type()
-	   && Linemap::is_predeclared_location(this->type_value()->location()))
-    {
-      // We don't need the package name for builtin types.
-      decl_name = Gogo::unpack_hidden_name(this->name_);
-    }
-  else
-    {
-      std::string package_name;
-      if (this->package_ == NULL)
-	package_name = gogo->package_name();
-      else
-	package_name = this->package_->package_name();
-
-      // Note that this will be misleading if this is an unexported
-      // method generated for an embedded imported type.  In that case
-      // the unexported method should have the package name of the
-      // package from which it is imported, but we are going to give
-      // it our package name.  Fixing this would require knowing the
-      // package name, but we only know the package path.  It might be
-      // better to use package paths here anyhow.  This doesn't affect
-      // the assembler code, because we always set that name in
-      // Function::get_or_make_decl anyhow.  FIXME.
-
-      decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
-
-      Function_type* fntype;
-      if (this->is_function())
-	fntype = this->func_value()->type();
-      else if (this->is_function_declaration())
-	fntype = this->func_declaration_value()->type();
-      else
-	fntype = NULL;
-      if (fntype != NULL && fntype->is_method())
-	{
-	  decl_name.push_back('.');
-	  decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
-	}
-    }
-  if (this->is_type())
-    {
-      unsigned int index;
-      const Named_object* in_function = this->type_value()->in_function(&index);
-      if (in_function != NULL)
-	{
-	  decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
-	  if (index > 0)
-	    {
-	      char buf[30];
-	      snprintf(buf, sizeof buf, "%u", index);
-	      decl_name += '$';
-	      decl_name += buf;
-	    }
-	}
-    }
-  return get_identifier_from_string(decl_name);
-}
-
 // Get a tree for a named object.
 
 tree
@@ -1067,11 +999,6 @@  Named_object::get_tree(Gogo* gogo, Named
       return error_mark_node;
     }
 
-  tree name;
-  if (this->classification_ == NAMED_OBJECT_TYPE)
-    name = NULL_TREE;
-  else
-    name = this->get_id(gogo);
   tree decl;
   switch (this->classification_)
     {
@@ -1099,6 +1026,7 @@  Named_object::get_tree(Gogo* gogo, Named
 	      decl = error_mark_node;
 	    else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
 	      {
+                tree name = get_identifier_from_string(this->get_id(gogo));
 		decl = build_decl(named_constant->location().gcc_location(),
                                   CONST_DECL, name, TREE_TYPE(expr_tree));
 		DECL_INITIAL(decl) = expr_tree;
@@ -1161,7 +1089,7 @@  Named_object::get_tree(Gogo* gogo, Named
     case NAMED_OBJECT_FUNC:
       {
 	Function* func = this->u_.func_value;
-	decl = func->get_or_make_decl(gogo, this, name);
+	decl = function_to_tree(func->get_or_make_decl(gogo, this));
 	if (decl != error_mark_node)
 	  {
 	    if (func->block() != NULL)
@@ -1286,123 +1214,12 @@  Variable::get_init_block(Gogo* gogo, Nam
   return block_tree;
 }
 
-// Get a tree for a function decl.
+// Get the backend representation.
 
-tree
-Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+Bfunction*
+Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
 {
-  if (this->fndecl_ == NULL_TREE)
-    {
-      tree functype = type_to_tree(this->type_->get_backend(gogo));
-
-      if (functype != error_mark_node)
-	{
-	  // The type of a function comes back as a pointer to a
-	  // struct whose first field is the function, but we want the
-	  // real function type for a function declaration.
-	  go_assert(POINTER_TYPE_P(functype)
-		    && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE);
-	  functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
-	  go_assert(FUNCTION_POINTER_TYPE_P(functype));
-	  functype = TREE_TYPE(functype);
-	}
-
-      if (functype == error_mark_node)
-	this->fndecl_ = error_mark_node;
-      else
-	{
-	  tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL,
-                                 id, functype);
-
-	  this->fndecl_ = decl;
-
-	  if (no->package() != NULL)
-	    ;
-	  else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
-	    ;
-	  else if (Gogo::unpack_hidden_name(no->name()) == "init"
-		   && !this->type_->is_method())
-	    ;
-	  else if (Gogo::unpack_hidden_name(no->name()) == "main"
-		   && gogo->is_main_package())
-	    TREE_PUBLIC(decl) = 1;
-	  // Methods have to be public even if they are hidden because
-	  // they can be pulled into type descriptors when using
-	  // anonymous fields.
-	  else if (!Gogo::is_hidden_name(no->name())
-		   || this->type_->is_method())
-	    {
-	      TREE_PUBLIC(decl) = 1;
-	      std::string pkgpath = gogo->pkgpath_symbol();
-	      if (this->type_->is_method()
-		  && Gogo::is_hidden_name(no->name())
-		  && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
-		{
-		  // This is a method we created for an unexported
-		  // method of an imported embedded type.  We need to
-		  // use the pkgpath of the imported package to avoid
-		  // a possible name collision.  See bug478 for a test
-		  // case.
-		  pkgpath = Gogo::hidden_name_pkgpath(no->name());
-		  pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
-		}
-
-	      std::string asm_name = pkgpath;
-	      asm_name.append(1, '.');
-	      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));
-	    }
-
-	  // Why do we have to do this in the frontend?
-	  tree restype = TREE_TYPE(functype);
-	  tree resdecl =
-            build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE,
-                       restype);
-	  DECL_ARTIFICIAL(resdecl) = 1;
-	  DECL_IGNORED_P(resdecl) = 1;
-	  DECL_CONTEXT(resdecl) = decl;
-	  DECL_RESULT(decl) = resdecl;
-
-	  // If a function calls the predeclared recover function, we
-	  // can't inline it, because recover behaves differently in a
-	  // function passed directly to defer.  If this is a recover
-	  // thunk that we built to test whether a function can be
-	  // recovered, we can't inline it, because that will mess up
-	  // our return address comparison.
-	  if (this->calls_recover_ || this->is_recover_thunk_)
-	    DECL_UNINLINABLE(decl) = 1;
-
-	  // If this is a thunk created to call a function which calls
-	  // the predeclared recover function, we need to disable
-	  // stack splitting for the thunk.
-	  if (this->is_recover_thunk_)
-	    {
-	      tree attr = get_identifier("__no_split_stack__");
-	      DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
-	    }
-
-	  if (this->in_unique_section_)
-	    resolve_unique_section (decl, 0, 1);
-
-	  go_preserve_from_gc(decl);
-	}
-    }
-  return this->fndecl_;
-}
-
-// Get a tree for a function declaration.
-
-tree
-Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
-{
-  if (this->fndecl_ == NULL_TREE)
+  if (this->fndecl_ == NULL)
     {
       // Let Go code use an asm declaration to pick up a builtin
       // function.
@@ -1412,56 +1229,44 @@  Function_declaration::get_or_make_decl(G
 	    builtin_functions.find(this->asm_name_);
 	  if (p != builtin_functions.end())
 	    {
-	      this->fndecl_ = p->second;
+	      this->fndecl_ = tree_to_function(p->second);
 	      return this->fndecl_;
 	    }
 	}
 
-      tree functype = type_to_tree(this->fntype_->get_backend(gogo));
+      std::string asm_name;
+      if (this->asm_name_.empty())
+        {
+          asm_name = (no->package() == NULL
+                                  ? gogo->pkgpath_symbol()
+                                  : no->package()->pkgpath_symbol());
+          asm_name.append(1, '.');
+          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));
+            }
+        }
+
+      Btype* functype = this->fntype_->get_backend_fntype(gogo);
+      this->fndecl_ =
+          gogo->backend()->function(functype, no->get_id(gogo), asm_name,
+                                    true, true, true, false, false,
+                                    this->location());
+    }
 
-      if (functype != error_mark_node)
-	{
-	  // The type of a function comes back as a pointer to a
-	  // struct whose first field is the function, but we want the
-	  // real function type for a function declaration.
-	  go_assert(POINTER_TYPE_P(functype)
-		    && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE);
-	  functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
-	  go_assert(FUNCTION_POINTER_TYPE_P(functype));
-	  functype = TREE_TYPE(functype);
-	}
+  return this->fndecl_;
+}
 
-      tree decl;
-      if (functype == error_mark_node)
-	decl = error_mark_node;
-      else
-	{
-	  decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id,
-                            functype);
-	  TREE_PUBLIC(decl) = 1;
-	  DECL_EXTERNAL(decl) = 1;
+// Return the function's decl after it has been built.
 
-	  if (this->asm_name_.empty())
-	    {
-	      std::string asm_name = (no->package() == NULL
-				      ? gogo->pkgpath_symbol()
-				      : no->package()->pkgpath_symbol());
-	      asm_name.append(1, '.');
-	      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));
-	    }
-	}
-      this->fndecl_ = decl;
-      go_preserve_from_gc(decl);
-    }
-  return this->fndecl_;
+tree
+Function::get_decl() const
+{
+  go_assert(this->fndecl_ != NULL);
+  return function_to_tree(this->fndecl_);
 }
 
 // We always pass the receiver to a method as a pointer.  If the
@@ -1558,7 +1363,7 @@  Function::copy_parm_to_heap(Gogo* gogo,
 void
 Function::build_tree(Gogo* gogo, Named_object* named_function)
 {
-  tree fndecl = this->fndecl_;
+  tree fndecl = this->get_decl();
   go_assert(fndecl != NULL_TREE);
 
   tree params = NULL_TREE;
@@ -1796,7 +1601,7 @@  Function::build_defer_wrapper(Gogo* gogo
     set = NULL_TREE;
   else
     set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
-			  DECL_RESULT(this->fndecl_), retval);
+			  DECL_RESULT(this->get_decl()), retval);
   tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
                                   void_type_node, set);
   append_to_statement_list(ret_stmt, &stmt_list);
@@ -1851,7 +1656,7 @@  Function::build_defer_wrapper(Gogo* gogo
       retval = this->return_value(gogo, named_function, end_loc,
 				  &stmt_list);
       set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
-			    DECL_RESULT(this->fndecl_), retval);
+			    DECL_RESULT(this->get_decl()), retval);
       ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
                                  void_type_node, set);
 
@@ -1869,7 +1674,7 @@  Function::build_defer_wrapper(Gogo* gogo
   *fini = stmt_list;
 }
 
-// Return the value to assign to DECL_RESULT(this->fndecl_).  This may
+// Return the value to assign to DECL_RESULT(this->get_decl()).  This may
 // also add statements to STMT_LIST, which need to be executed before
 // the assignment.  This is used for a return statement with no
 // explicit values.
@@ -1902,7 +1707,7 @@  Function::return_value(Gogo* gogo, Named
     }
   else
     {
-      tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
+      tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl()));
       retval = create_tmp_var(rettype, "RESULT");
       tree field = TYPE_FIELDS(rettype);
       int index = 0;
@@ -2323,18 +2128,14 @@  Gogo::interface_method_table_for_type(co
       go_assert(m != NULL);
 
       Named_object* no = m->named_object();
-
-      tree fnid = no->get_id(this);
-
-      tree fndecl;
+      Bfunction* bf;
       if (no->is_function())
-	fndecl = no->func_value()->get_or_make_decl(this, no, fnid);
+	bf = no->func_value()->get_or_make_decl(this, no);
       else if (no->is_function_declaration())
-	fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
-								fnid);
+	bf = no->func_declaration_value()->get_or_make_decl(this, no);
       else
 	go_unreachable();
-      fndecl = build_fold_addr_expr(fndecl);
+      tree fndecl = build_fold_addr_expr(function_to_tree(bf));
 
       elt = pointers->quick_push(empty);
       elt->index = size_int(i);
@@ -2353,10 +2154,11 @@  Gogo::interface_method_table_for_type(co
   TREE_CONSTANT(decl) = 1;
   DECL_INITIAL(decl) = constructor;
 
-  // If the interface type has hidden methods, then this is the only
-  // definition of the table.  Otherwise it is a comdat table which
-  // may be defined in multiple packages.
-  if (has_hidden_methods)
+  // If the interface type has hidden methods, and the table is for a
+  // named type, then this is the only definition of the table.
+  // Otherwise it is a comdat table which may be defined in multiple
+  // packages.
+  if (has_hidden_methods && type->named_type() != NULL)
     TREE_PUBLIC(decl) = 1;
   else
     {
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 203707)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -3320,7 +3320,8 @@  Function::Function(Function_type* type,
     closure_var_(NULL), block_(block), location_(location), labels_(),
     local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL),
     is_sink_(false), results_are_named_(false), nointerface_(false),
-    calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false),
+    is_unnamed_type_stub_method_(false), calls_recover_(false),
+    is_recover_thunk_(false), has_recover_thunk_(false),
     in_unique_section_(false)
 {
 }
@@ -3819,6 +3820,81 @@  Function::import_func(Import* imp, std::
   *presults = results;
 }
 
+// Get the backend representation.
+
+Bfunction*
+Function::get_or_make_decl(Gogo* gogo, Named_object* no)
+{
+  if (this->fndecl_ == NULL)
+    {
+      std::string asm_name;
+      bool is_visible = false;
+      if (no->package() != NULL)
+        ;
+      else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
+        ;
+      else if (Gogo::unpack_hidden_name(no->name()) == "init"
+               && !this->type_->is_method())
+        ;
+      else if (Gogo::unpack_hidden_name(no->name()) == "main"
+               && gogo->is_main_package())
+        is_visible = true;
+      // Methods have to be public even if they are hidden because
+      // they can be pulled into type descriptors when using
+      // anonymous fields.
+      else if (!Gogo::is_hidden_name(no->name())
+               || this->type_->is_method())
+        {
+	  if (!this->is_unnamed_type_stub_method_)
+	    is_visible = true;
+          std::string pkgpath = gogo->pkgpath_symbol();
+          if (this->type_->is_method()
+              && Gogo::is_hidden_name(no->name())
+              && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
+            {
+              // This is a method we created for an unexported
+              // method of an imported embedded type.  We need to
+              // use the pkgpath of the imported package to avoid
+              // a possible name collision.  See bug478 for a test
+              // case.
+              pkgpath = Gogo::hidden_name_pkgpath(no->name());
+              pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
+            }
+
+          asm_name = pkgpath;
+          asm_name.append(1, '.');
+          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));
+            }
+        }
+
+      // If a function calls the predeclared recover function, we
+      // can't inline it, because recover behaves differently in a
+      // function passed directly to defer.  If this is a recover
+      // thunk that we built to test whether a function can be
+      // recovered, we can't inline it, because that will mess up
+      // our return address comparison.
+      bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_);
+
+      // If this is a thunk created to call a function which calls
+      // the predeclared recover function, we need to disable
+      // stack splitting for the thunk.
+      bool disable_split_stack = this->is_recover_thunk_;
+
+      Btype* functype = this->type_->get_backend_fntype(gogo);
+      this->fndecl_ =
+          gogo->backend()->function(functype, no->get_id(gogo), asm_name,
+                                    is_visible, false, is_inlinable,
+                                    disable_split_stack,
+                                    this->in_unique_section_, this->location());
+    }
+  return this->fndecl_;
+}
+
 // Class Block.
 
 Block::Block(Block* enclosing, Location location)
@@ -5110,6 +5186,75 @@  Named_object::get_backend_variable(Gogo*
     go_unreachable();
 }
 
+
+// Return the external identifier for this object.
+
+std::string
+Named_object::get_id(Gogo* gogo)
+{
+  go_assert(!this->is_variable() && !this->is_result_variable());
+  std::string decl_name;
+  if (this->is_function_declaration()
+      && !this->func_declaration_value()->asm_name().empty())
+    decl_name = this->func_declaration_value()->asm_name();
+  else if (this->is_type()
+	   && Linemap::is_predeclared_location(this->type_value()->location()))
+    {
+      // We don't need the package name for builtin types.
+      decl_name = Gogo::unpack_hidden_name(this->name_);
+    }
+  else
+    {
+      std::string package_name;
+      if (this->package_ == NULL)
+	package_name = gogo->package_name();
+      else
+	package_name = this->package_->package_name();
+
+      // Note that this will be misleading if this is an unexported
+      // method generated for an embedded imported type.  In that case
+      // the unexported method should have the package name of the
+      // package from which it is imported, but we are going to give
+      // it our package name.  Fixing this would require knowing the
+      // package name, but we only know the package path.  It might be
+      // better to use package paths here anyhow.  This doesn't affect
+      // the assembler code, because we always set that name in
+      // Function::get_or_make_decl anyhow.  FIXME.
+
+      decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
+
+      Function_type* fntype;
+      if (this->is_function())
+	fntype = this->func_value()->type();
+      else if (this->is_function_declaration())
+	fntype = this->func_declaration_value()->type();
+      else
+	fntype = NULL;
+      if (fntype != NULL && fntype->is_method())
+	{
+	  decl_name.push_back('.');
+	  decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
+	}
+    }
+  if (this->is_type())
+    {
+      unsigned int index;
+      const Named_object* in_function = this->type_value()->in_function(&index);
+      if (in_function != NULL)
+	{
+	  decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+	  if (index > 0)
+	    {
+	      char buf[30];
+	      snprintf(buf, sizeof buf, "%u", index);
+	      decl_name += '$';
+	      decl_name += buf;
+	    }
+	}
+    }
+  return decl_name;
+}
+
 // Class Bindings.
 
 Bindings::Bindings(Bindings* enclosing)
Index: gcc/go/gofrontend/runtime.def
===================================================================
--- gcc/go/gofrontend/runtime.def	(revision 203707)
+++ gcc/go/gofrontend/runtime.def	(working copy)
@@ -68,6 +68,12 @@  DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__g
 	       P1(STRING), R1(SLICE))
 
 
+// Complex division.
+DEF_GO_RUNTIME(COMPLEX64_DIV, "__go_complex64_div",
+	       P2(COMPLEX64, COMPLEX64), R1(COMPLEX64))
+DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
+	       P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
+
 // Make a slice.
 DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
 DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 203707)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -3383,6 +3383,68 @@  Function_type::do_hash_for_method(Gogo*
 // Get the backend representation for a function type.
 
 Btype*
+Function_type::get_backend_fntype(Gogo* gogo)
+{
+  if (this->fnbtype_ == NULL)
+    {
+      Backend::Btyped_identifier breceiver;
+      if (this->receiver_ != NULL)
+        {
+          breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
+
+          // We always pass the address of the receiver parameter, in
+          // order to make interface calls work with unknown types.
+          Type* rtype = this->receiver_->type();
+          if (rtype->points_to() == NULL)
+            rtype = Type::make_pointer_type(rtype);
+          breceiver.btype = rtype->get_backend(gogo);
+          breceiver.location = this->receiver_->location();
+        }
+
+      std::vector<Backend::Btyped_identifier> bparameters;
+      if (this->parameters_ != NULL)
+        {
+          bparameters.resize(this->parameters_->size());
+          size_t i = 0;
+          for (Typed_identifier_list::const_iterator p =
+                   this->parameters_->begin(); p != this->parameters_->end();
+               ++p, ++i)
+	    {
+              bparameters[i].name = Gogo::unpack_hidden_name(p->name());
+              bparameters[i].btype = p->type()->get_backend(gogo);
+              bparameters[i].location = p->location();
+            }
+          go_assert(i == bparameters.size());
+        }
+
+      std::vector<Backend::Btyped_identifier> bresults;
+      if (this->results_ != NULL)
+        {
+          bresults.resize(this->results_->size());
+          size_t i = 0;
+          for (Typed_identifier_list::const_iterator p =
+                   this->results_->begin(); p != this->results_->end();
+               ++p, ++i)
+	    {
+              bresults[i].name = Gogo::unpack_hidden_name(p->name());
+              bresults[i].btype = p->type()->get_backend(gogo);
+              bresults[i].location = p->location();
+            }
+          go_assert(i == bresults.size());
+        }
+
+      this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters,
+                                                      bresults,
+                                                      this->location());
+
+    }
+
+  return this->fnbtype_;
+}
+
+// Get the backend representation for a Go function type.
+
+Btype*
 Function_type::do_get_backend(Gogo* gogo)
 {
   // When we do anything with a function value other than call it, it
@@ -3395,57 +3457,9 @@  Function_type::do_get_backend(Gogo* gogo
     gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
   Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
 
-  Backend::Btyped_identifier breceiver;
-  if (this->receiver_ != NULL)
-    {
-      breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
-
-      // We always pass the address of the receiver parameter, in
-      // order to make interface calls work with unknown types.
-      Type* rtype = this->receiver_->type();
-      if (rtype->points_to() == NULL)
-	rtype = Type::make_pointer_type(rtype);
-      breceiver.btype = rtype->get_backend(gogo);
-      breceiver.location = this->receiver_->location();
-    }
-
-  std::vector<Backend::Btyped_identifier> bparameters;
-  if (this->parameters_ != NULL)
-    {
-      bparameters.resize(this->parameters_->size());
-      size_t i = 0;
-      for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
-	   p != this->parameters_->end();
-	   ++p, ++i)
-	{
-	  bparameters[i].name = Gogo::unpack_hidden_name(p->name());
-	  bparameters[i].btype = p->type()->get_backend(gogo);
-	  bparameters[i].location = p->location();
-	}
-      go_assert(i == bparameters.size());
-    }
-
-  std::vector<Backend::Btyped_identifier> bresults;
-  if (this->results_ != NULL)
-    {
-      bresults.resize(this->results_->size());
-      size_t i = 0;
-      for (Typed_identifier_list::const_iterator p = this->results_->begin();
-	   p != this->results_->end();
-	   ++p, ++i)
-	{
-	  bresults[i].name = Gogo::unpack_hidden_name(p->name());
-	  bresults[i].btype = p->type()->get_backend(gogo);
-	  bresults[i].location = p->location();
-	}
-      go_assert(i == bresults.size());
-    }
-
-  Btype* fntype = gogo->backend()->function_type(breceiver, bparameters,
-						 bresults, loc);
   std::vector<Backend::Btyped_identifier> fields(1);
   fields[0].name = "code";
-  fields[0].btype = fntype;
+  fields[0].btype = this->get_backend_fntype(gogo);
   fields[0].location = loc;
   if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields))
     return gogo->backend()->error_type();
@@ -4264,12 +4278,7 @@  Struct_type::do_verify()
        ++p)
     {
       Type* t = p->type();
-      if (t->is_undefined())
-	{
-	  error_at(p->location(), "struct field type is incomplete");
-	  p->set_type(Type::make_error_type());
-	}
-      else if (p->is_anonymous())
+      if (p->is_anonymous())
 	{
 	  if (t->named_type() != NULL && t->points_to() != NULL)
 	    {
@@ -5249,6 +5258,19 @@  Struct_type::do_import(Import* imp)
 	    }
 	  Type* ftype = imp->read_type();
 
+	  // We don't pack the names of builtin types.  In
+	  // Struct_field::is_field_name we cope with a hack.  Now we
+	  // need another hack so that we don't accidentally think
+	  // that an embedded builtin type is accessible from another
+	  // package (we know that all the builtin types are not
+	  // exported).
+	  if (name.empty() && ftype->deref()->named_type() != NULL)
+	    {
+	      const std::string fn(ftype->deref()->named_type()->name());
+	      if (fn[0] >= 'a' && fn[0] <= 'z')
+		name = '.' + imp->package()->pkgpath() + '.' + fn;
+	    }
+
 	  Struct_field sf(Typed_identifier(name, ftype, imp->location()));
 
 	  if (imp->peek_char() == ' ')
@@ -9022,6 +9044,8 @@  Type::build_stub_methods(Gogo* gogo, con
 				      fntype->is_varargs(), location);
 	  gogo->finish_function(fntype->location());
 
+	  if (type->named_type() == NULL && stub->is_function())
+	    stub->func_value()->set_is_unnamed_type_stub_method();
 	  if (m->nointerface() && stub->is_function())
 	    stub->func_value()->set_nointerface();
 	}
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 203707)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -1717,7 +1717,8 @@  class Function_type : public Type
 		Typed_identifier_list* results, Location location)
     : Type(TYPE_FUNCTION),
       receiver_(receiver), parameters_(parameters), results_(results),
-      location_(location), is_varargs_(false), is_builtin_(false)
+      location_(location), is_varargs_(false), is_builtin_(false),
+      fnbtype_(NULL)
   { }
 
   // Get the receiver.
@@ -1798,6 +1799,11 @@  class Function_type : public Type
   static Type*
   make_function_type_descriptor_type();
 
+  // Return the backend representation of this function type. This is used
+  // as the real type of a backend function declaration or defintion.
+  Btype*
+  get_backend_fntype(Gogo*);
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1851,6 +1857,9 @@  class Function_type : public Type
   // Whether this is a special builtin function which can not simply
   // be called.  This is used for len, cap, etc.
   bool is_builtin_;
+  // The backend representation of this type for backend function
+  // declarations and definitions.
+  Btype* fnbtype_;
 };
 
 // The type of a pointer.