OSDN Git Service

compiler: Better error message if method requires pointer receiver.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / types.cc
index 61ec555..ebf2ed9 100644 (file)
@@ -588,6 +588,9 @@ Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1,
               p != fields->end();
               ++p)
            {
+             if (Gogo::is_sink_name(p->field_name()))
+               continue;
+
              if (!p->type()->is_comparable())
                {
                  if (reason != NULL)
@@ -622,16 +625,24 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
                                  std::string* reason)
 {
   // Do some checks first.  Make sure the types are defined.
-  if (rhs != NULL
-      && rhs->forwarded()->forward_declaration_type() == NULL
-      && rhs->is_void_type())
+  if (rhs != NULL && !rhs->is_undefined())
     {
-      if (reason != NULL)
-       *reason = "non-value used as value";
-      return false;
+      if (rhs->is_void_type())
+       {
+         if (reason != NULL)
+           *reason = "non-value used as value";
+         return false;
+       }
+      if (rhs->is_call_multiple_result_type())
+       {
+         if (reason != NULL)
+           reason->assign(_("multiple value function call in "
+                            "single value context"));
+         return false;
+       }
     }
 
-  if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL)
+  if (lhs != NULL && !lhs->is_undefined())
     {
       // Any value may be assigned to the blank identifier.
       if (lhs->is_sink_type())
@@ -639,9 +650,7 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
 
       // All fields of a struct must be exported, or the assignment
       // must be in the same package.
-      if (check_hidden_fields
-         && rhs != NULL
-         && rhs->forwarded()->forward_declaration_type() == NULL)
+      if (check_hidden_fields && rhs != NULL && !rhs->is_undefined())
        {
          if (lhs->has_hidden_fields(NULL, reason)
              || rhs->has_hidden_fields(NULL, reason))
@@ -715,9 +724,6 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
     {
       if (rhs->interface_type() != NULL)
        reason->assign(_("need explicit conversion"));
-      else if (rhs->is_call_multiple_result_type())
-       reason->assign(_("multiple value function call in "
-                        "single value context"));
       else if (lhs->named_type() != NULL && rhs->named_type() != NULL)
        {
          size_t len = (lhs->named_type()->name().length()
@@ -1292,29 +1298,45 @@ Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
     return "__go_td_" + this->mangled_name(gogo);
 
   Named_object* no = nt->named_object();
-  const Named_object* in_function = nt->in_function();
+  unsigned int index;
+  const Named_object* in_function = nt->in_function(&index);
   std::string ret = "__go_tdn_";
   if (nt->is_builtin())
     go_assert(in_function == NULL);
   else
     {
-      const std::string& unique_prefix(no->package() == NULL
-                                      ? gogo->unique_prefix()
-                                      : no->package()->unique_prefix());
-      const std::string& package_name(no->package() == NULL
-                                     ? gogo->package_name()
-                                     : no->package()->name());
-      ret.append(unique_prefix);
-      ret.append(1, '.');
-      ret.append(package_name);
+      const std::string& pkgpath(no->package() == NULL
+                                ? gogo->pkgpath_symbol()
+                                : no->package()->pkgpath_symbol());
+      ret.append(pkgpath);
       ret.append(1, '.');
       if (in_function != NULL)
        {
          ret.append(Gogo::unpack_hidden_name(in_function->name()));
          ret.append(1, '.');
+         if (index > 0)
+           {
+             char buf[30];
+             snprintf(buf, sizeof buf, "%u", index);
+             ret.append(buf);
+             ret.append(1, '.');
+           }
        }
     }
-  ret.append(no->name());
+
+  // FIXME: This adds in pkgpath twice for hidden symbols, which is
+  // pointless.
+  const std::string& name(no->name());
+  if (!Gogo::is_hidden_name(name))
+    ret.append(name);
+  else
+    {
+      ret.append(1, '.');
+      ret.append(Gogo::pkgpath_for_symbol(Gogo::hidden_name_pkgpath(name)));
+      ret.append(1, '.');
+      ret.append(Gogo::unpack_hidden_name(name));
+    }
+
   return ret;
 }
 
@@ -1735,9 +1757,19 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name,
     {
       // This name is already hidden or not as appropriate.
       base_name = name->name();
-      const Named_object* in_function = name->in_function();
+      unsigned int index;
+      const Named_object* in_function = name->in_function(&index);
       if (in_function != NULL)
-       base_name += '$' + in_function->name();
+       {
+         base_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+         if (index > 0)
+           {
+             char buf[30];
+             snprintf(buf, sizeof buf, "%u", index);
+             base_name += '$';
+             base_name += buf;
+           }
+       }
     }
   std::string hash_name = base_name + "$hash";
   std::string equal_name = base_name + "$equal";
@@ -1787,6 +1819,12 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
 {
   Location bloc = Linemap::predeclared_location();
 
+  if (gogo->specific_type_functions_are_written())
+    {
+      go_assert(saw_errors());
+      return;
+    }
+
   Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false,
                                               bloc);
   gogo->start_block(bloc);
@@ -1968,19 +2006,23 @@ Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type,
       else
        {
          const Package* package = no->package();
-         const std::string& unique_prefix(package == NULL
-                                          ? gogo->unique_prefix()
-                                          : package->unique_prefix());
-         const std::string& package_name(package == NULL
-                                         ? gogo->package_name()
-                                         : package->name());
-         n.assign(unique_prefix);
-         n.append(1, '.');
-         n.append(package_name);
-         if (name->in_function() != NULL)
+         const std::string& pkgpath(package == NULL
+                                    ? gogo->pkgpath()
+                                    : package->pkgpath());
+         n.assign(pkgpath);
+         unsigned int index;
+         const Named_object* in_function = name->in_function(&index);
+         if (in_function != NULL)
            {
              n.append(1, '.');
-             n.append(Gogo::unpack_hidden_name(name->in_function()->name()));
+             n.append(Gogo::unpack_hidden_name(in_function->name()));
+             if (index > 0)
+               {
+                 char buf[30];
+                 snprintf(buf, sizeof buf, "%u", index);
+                 n.append(1, '.');
+                 n.append(buf);
+               }
            }
          s = Expression::make_string(n, bloc);
          vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
@@ -2087,7 +2129,8 @@ Type::method_constructor(Gogo*, Type* method_type,
     vals->push_back(Expression::make_nil(bloc));
   else
     {
-      s = Expression::make_string(Gogo::hidden_name_prefix(method_name), bloc);
+      s = Expression::make_string(Gogo::hidden_name_pkgpath(method_name),
+                                 bloc);
       vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
     }
 
@@ -2221,15 +2264,13 @@ Type::is_backend_type_size_known(Gogo* gogo)
          return true;
        else
          {
+           Numeric_constant nc;
+           if (!at->length()->numeric_constant_value(&nc))
+             return false;
            mpz_t ival;
-           mpz_init(ival);
-           Type* dummy;
-           bool length_known = at->length()->integer_constant_value(true,
-                                                                    ival,
-                                                                    &dummy);
-           mpz_clear(ival);
-           if (!length_known)
+           if (!nc.to_int(&ival))
              return false;
+           mpz_clear(ival);
            return at->element_type()->is_backend_type_size_known(gogo);
          }
       }
@@ -3111,9 +3152,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
   // A redeclaration of a function is required to use the same names
   // for the receiver and parameters.
   if (this->receiver() != NULL
-      && this->receiver()->name() != t->receiver()->name()
-      && this->receiver()->name() != Import::import_marker
-      && t->receiver()->name() != Import::import_marker)
+      && this->receiver()->name() != t->receiver()->name())
     {
       if (reason != NULL)
        *reason = "receiver name changed";
@@ -3129,9 +3168,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
           p2 != parms2->end();
           ++p2, ++p1)
        {
-         if (p1->name() != p2->name()
-             && p1->name() != Import::import_marker
-             && p2->name() != Import::import_marker)
+         if (p1->name() != p2->name())
            {
              if (reason != NULL)
                *reason = "parameter name changed";
@@ -3160,9 +3197,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
           res2 != results2->end();
           ++res2, ++res1)
        {
-         if (res1->name() != res2->name()
-             && res1->name() != Import::import_marker
-             && res2->name() != Import::import_marker)
+         if (res1->name() != res2->name())
            {
              if (reason != NULL)
                *reason = "result name changed";
@@ -3609,6 +3644,8 @@ Function_type::do_export(Export* exp) const
            first = false;
          else
            exp->write_c_string(", ");
+         exp->write_name(p->name());
+         exp->write_c_string(" ");
          if (!is_varargs || p + 1 != this->parameters_->end())
            exp->write_type(p->type());
          else
@@ -3624,7 +3661,7 @@ Function_type::do_export(Export* exp) const
   if (results != NULL)
     {
       exp->write_c_string(" ");
-      if (results->size() == 1)
+      if (results->size() == 1 && results->begin()->name().empty())
        exp->write_type(results->begin()->type());
       else
        {
@@ -3638,6 +3675,8 @@ Function_type::do_export(Export* exp) const
                first = false;
              else
                exp->write_c_string(", ");
+             exp->write_name(p->name());
+             exp->write_c_string(" ");
              exp->write_type(p->type());
            }
          exp->write_c_string(")");
@@ -3660,6 +3699,9 @@ Function_type::do_import(Import* imp)
       parameters = new Typed_identifier_list();
       while (true)
        {
+         std::string name = imp->read_name();
+         imp->require_c_string(" ");
+
          if (imp->match_c_string("..."))
            {
              imp->advance(3);
@@ -3669,8 +3711,8 @@ Function_type::do_import(Import* imp)
          Type* ptype = imp->read_type();
          if (is_varargs)
            ptype = Type::make_array_type(ptype, NULL);
-         parameters->push_back(Typed_identifier(Import::import_marker,
-                                                ptype, imp->location()));
+         parameters->push_back(Typed_identifier(name, ptype,
+                                                imp->location()));
          if (imp->peek_char() != ',')
            break;
          go_assert(!is_varargs);
@@ -3689,17 +3731,18 @@ Function_type::do_import(Import* imp)
       if (imp->peek_char() != '(')
        {
          Type* rtype = imp->read_type();
-         results->push_back(Typed_identifier(Import::import_marker, rtype,
-                                             imp->location()));
+         results->push_back(Typed_identifier("", rtype, imp->location()));
        }
       else
        {
          imp->advance(1);
          while (true)
            {
+             std::string name = imp->read_name();
+             imp->require_c_string(" ");
              Type* rtype = imp->read_type();
-             results->push_back(Typed_identifier(Import::import_marker,
-                                                 rtype, imp->location()));
+             results->push_back(Typed_identifier(name, rtype,
+                                                 imp->location()));
              if (imp->peek_char() != ',')
                break;
              imp->require_c_string(", ");
@@ -3739,8 +3782,12 @@ Function_type::copy_with_receiver(Type* receiver_type) const
   go_assert(!this->is_method());
   Typed_identifier* receiver = new Typed_identifier("", receiver_type,
                                                    this->location_);
-  return Type::make_function_type(receiver, this->parameters_,
-                                 this->results_, this->location_);
+  Function_type* ret = Type::make_function_type(receiver, this->parameters_,
+                                               this->results_,
+                                               this->location_);
+  if (this->is_varargs_)
+    ret->set_is_varargs();
+  return ret;
 }
 
 // Make a function type.
@@ -4114,7 +4161,6 @@ Struct_type::do_verify()
   Struct_field_list* fields = this->fields_;
   if (fields == NULL)
     return true;
-  bool ret = true;
   for (Struct_field_list::iterator p = fields->begin();
        p != fields->end();
        ++p)
@@ -4124,7 +4170,6 @@ Struct_type::do_verify()
        {
          error_at(p->location(), "struct field type is incomplete");
          p->set_type(Type::make_error_type());
-         ret = false;
        }
       else if (p->is_anonymous())
        {
@@ -4132,19 +4177,17 @@ Struct_type::do_verify()
            {
              error_at(p->location(), "embedded type may not be a pointer");
              p->set_type(Type::make_error_type());
-             return false;
            }
-         if (t->points_to() != NULL
-             && t->points_to()->interface_type() != NULL)
+         else if (t->points_to() != NULL
+                  && t->points_to()->interface_type() != NULL)
            {
              error_at(p->location(),
                       "embedded type may not be pointer to interface");
              p->set_type(Type::make_error_type());
-             return false;
            }
        }
     }
-  return ret;
+  return true;
 }
 
 // Whether this contains a pointer.
@@ -4263,6 +4306,9 @@ Struct_type::do_compare_is_identity(Gogo* gogo) const
        pf != fields->end();
        ++pf)
     {
+      if (Gogo::is_sink_name(pf->field_name()))
+       return false;
+
       if (!pf->type()->compare_is_identity(gogo))
        return false;
 
@@ -4659,7 +4705,7 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name)
        fvals->push_back(Expression::make_nil(bloc));
       else
        {
-         std::string n = Gogo::hidden_name_prefix(pf->field_name());
+         std::string n = Gogo::hidden_name_pkgpath(pf->field_name());
          Expression* s = Expression::make_string(n, bloc);
          fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
        }
@@ -4736,6 +4782,9 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*,
        pf != fields->end();
        ++pf)
     {
+      if (Gogo::is_sink_name(pf->field_name()))
+       continue;
+
       if (first)
        first = false;
       else
@@ -4827,6 +4876,9 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
        pf != fields->end();
        ++pf, ++field_index)
     {
+      if (Gogo::is_sink_name(pf->field_name()))
+       continue;
+
       // Compare one field in both P1 and P2.
       Expression* f1 = Expression::make_temporary_reference(p1, bloc);
       f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
@@ -5095,17 +5147,22 @@ Array_type::is_identical(const Array_type* t, bool errors_are_identical) const
       // Try to determine the lengths.  If we can't, assume the arrays
       // are not identical.
       bool ret = false;
-      mpz_t v1;
-      mpz_init(v1);
-      Type* type1;
-      mpz_t v2;
-      mpz_init(v2);
-      Type* type2;
-      if (l1->integer_constant_value(true, v1, &type1)
-         && l2->integer_constant_value(true, v2, &type2))
-       ret = mpz_cmp(v1, v2) == 0;
-      mpz_clear(v1);
-      mpz_clear(v2);
+      Numeric_constant nc1, nc2;
+      if (l1->numeric_constant_value(&nc1)
+         && l2->numeric_constant_value(&nc2))
+       {
+         mpz_t v1;
+         if (nc1.to_int(&v1))
+           {
+             mpz_t v2;
+             if (nc2.to_int(&v2))
+               {
+                 ret = mpz_cmp(v1, v2) == 0;
+                 mpz_clear(v2);
+               }
+             mpz_clear(v1);
+           }
+       }
       return ret;
     }
 
@@ -5143,58 +5200,44 @@ Array_type::verify_length()
       return false;
     }
 
-  mpz_t val;
-  mpz_init(val);
-  Type* vt;
-  if (!this->length_->integer_constant_value(true, val, &vt))
+  Numeric_constant nc;
+  if (!this->length_->numeric_constant_value(&nc))
     {
-      mpfr_t fval;
-      mpfr_init(fval);
-      if (!this->length_->float_constant_value(fval, &vt))
-       {
-         if (this->length_->type()->integer_type() != NULL
-             || this->length_->type()->float_type() != NULL)
-           error_at(this->length_->location(),
-                    "array bound is not constant");
-         else
-           error_at(this->length_->location(),
-                    "array bound is not numeric");
-         mpfr_clear(fval);
-         mpz_clear(val);
-         return false;
-       }
-      if (!mpfr_integer_p(fval))
-       {
-         error_at(this->length_->location(),
-                  "array bound truncated to integer");
-         mpfr_clear(fval);
-         mpz_clear(val);
-         return false;
-       }
-      mpz_init(val);
-      mpfr_get_z(val, fval, GMP_RNDN);
-      mpfr_clear(fval);
+      if (this->length_->type()->integer_type() != NULL
+         || this->length_->type()->float_type() != NULL)
+       error_at(this->length_->location(), "array bound is not constant");
+      else
+       error_at(this->length_->location(), "array bound is not numeric");
+      return false;
     }
 
-  if (mpz_sgn(val) < 0)
+  unsigned long val;
+  switch (nc.to_unsigned_long(&val))
     {
+    case Numeric_constant::NC_UL_VALID:
+      break;
+    case Numeric_constant::NC_UL_NOTINT:
+      error_at(this->length_->location(), "array bound truncated to integer");
+      return false;
+    case Numeric_constant::NC_UL_NEGATIVE:
       error_at(this->length_->location(), "negative array bound");
-      mpz_clear(val);
       return false;
+    case Numeric_constant::NC_UL_BIG:
+      error_at(this->length_->location(), "array bound overflows");
+      return false;
+    default:
+      go_unreachable();
     }
 
   Type* int_type = Type::lookup_integer_type("int");
-  int tbits = int_type->integer_type()->bits();
-  int vbits = mpz_sizeinbase(val, 2);
-  if (vbits + 1 > tbits)
+  unsigned int tbits = int_type->integer_type()->bits();
+  if (sizeof(val) <= tbits * 8
+      && val >> (tbits - 1) != 0)
     {
       error_at(this->length_->location(), "array bound overflows");
-      mpz_clear(val);
       return false;
     }
 
-  mpz_clear(val);
-
   return true;
 }
 
@@ -5204,10 +5247,7 @@ bool
 Array_type::do_verify()
 {
   if (!this->verify_length())
-    {
-      this->length_ = Expression::make_error(this->length_->location());
-      return false;
-    }
+    this->length_ = Expression::make_error(this->length_->location());
   return true;
 }
 
@@ -5449,11 +5489,16 @@ Array_type::get_length_tree(Gogo* gogo)
   go_assert(this->length_ != NULL);
   if (this->length_tree_ == NULL_TREE)
     {
+      Numeric_constant nc;
       mpz_t val;
-      mpz_init(val);
-      Type* t;
-      if (this->length_->integer_constant_value(true, val, &t))
+      if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
        {
+         if (mpz_sgn(val) < 0)
+           {
+             this->length_tree_ = error_mark_node;
+             return this->length_tree_;
+           }
+         Type* t = nc.type();
          if (t == NULL)
            t = Type::lookup_integer_type("int");
          else if (t->is_abstract())
@@ -5464,8 +5509,6 @@ Array_type::get_length_tree(Gogo* gogo)
        }
       else
        {
-         mpz_clear(val);
-
          // Make up a translation context for the array length
          // expression.  FIXME: This won't work in general.
          Translate_context context(gogo, NULL, NULL, NULL);
@@ -5816,23 +5859,17 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
   ret->push_back('[');
   if (this->length_ != NULL)
     {
-      mpz_t val;
-      mpz_init(val);
-      Type* type;
-      if (!this->length_->integer_constant_value(true, val, &type))
-       error_at(this->length_->location(),
-                "array length must be integer constant expression");
-      else if (mpz_cmp_si(val, 0) < 0)
-       error_at(this->length_->location(), "array length is negative");
-      else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
-       error_at(this->length_->location(), "array length is too large");
+      Numeric_constant nc;
+      unsigned long val;
+      if (!this->length_->numeric_constant_value(&nc)
+         || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
+       error_at(this->length_->location(), "invalid array length");
       else
        {
          char buf[50];
-         snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
+         snprintf(buf, sizeof buf, "%lu", val);
          ret->append(buf);
        }
-      mpz_clear(val);
     }
   ret->push_back(']');
 
@@ -5848,23 +5885,17 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
   this->append_mangled_name(this->element_type_, gogo, ret);
   if (this->length_ != NULL)
     {
-      mpz_t val;
-      mpz_init(val);
-      Type* type;
-      if (!this->length_->integer_constant_value(true, val, &type))
-       error_at(this->length_->location(),
-                "array length must be integer constant expression");
-      else if (mpz_cmp_si(val, 0) < 0)
-       error_at(this->length_->location(), "array length is negative");
-      else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
-       error_at(this->length_->location(), "array size is too large");
+      Numeric_constant nc;
+      unsigned long val;
+      if (!this->length_->numeric_constant_value(&nc)
+         || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
+       error_at(this->length_->location(), "invalid array length");
       else
        {
          char buf[50];
-         snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
+         snprintf(buf, sizeof buf, "%lu", val);
          ret->append(buf);
        }
-      mpz_clear(val);
     }
   ret->push_back('e');
 }
@@ -5897,10 +5928,7 @@ Map_type::do_verify()
 {
   // The runtime support uses "map[void]void".
   if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type())
-    {
-      error_at(this->location_, "invalid map key type");
-      return false;
-    }
+    error_at(this->location_, "invalid map key type");
   return true;
 }
 
@@ -6469,7 +6497,7 @@ Interface_type::finalize_methods()
        }
 
       Named_type* nt = t->named_type();
-      if (nt != NULL)
+      if (nt != NULL && it->parse_methods_ != NULL)
        {
          std::vector<Named_type*>::const_iterator q;
          for (q = seen.begin(); q != seen.end(); ++q)
@@ -6571,7 +6599,11 @@ bool
 Interface_type::is_identical(const Interface_type* t,
                             bool errors_are_identical) const
 {
-  go_assert(this->methods_are_finalized_ && t->methods_are_finalized_);
+  // If methods have not been finalized, then we are asking whether
+  // func redeclarations are the same.  This is an error, so for
+  // simplicity we say they are never the same.
+  if (!this->methods_are_finalized_ || !t->methods_are_finalized_)
+    return false;
 
   // We require the same methods with the same types.  The methods
   // have already been sorted.
@@ -6822,7 +6854,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
              std::string n = Gogo::message_name(p->name());
              size_t len = 100 + n.length();
              char* buf = new char[len];
-             snprintf(buf, len, _("method %s%s%s requires a pointer"),
+             snprintf(buf, len,
+                      _("method %s%s%s requires a pointer receiver"),
                       open_quote, n.c_str(), close_quote);
              reason->assign(buf);
              delete[] buf;
@@ -6886,10 +6919,37 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
        p != type->methods()->end();
        ++p, ++i)
     {
+      // The type of the method in Go only includes the parameters.
+      // The actual method also has a receiver, which is always a
+      // pointer.  We need to add that pointer type here in order to
+      // generate the correct type for the backend.
+      Function_type* ft = p->type()->function_type();
+      go_assert(ft->receiver() == NULL);
+
+      const Typed_identifier_list* params = ft->parameters();
+      Typed_identifier_list* mparams = new Typed_identifier_list();
+      if (params != NULL)
+       mparams->reserve(params->size() + 1);
+      Type* vt = Type::make_pointer_type(Type::make_void_type());
+      mparams->push_back(Typed_identifier("", vt, ft->location()));
+      if (params != NULL)
+       {
+         for (Typed_identifier_list::const_iterator pp = params->begin();
+              pp != params->end();
+              ++pp)
+           mparams->push_back(*pp);
+       }
+
+      Typed_identifier_list* mresults = (ft->results() == NULL
+                                        ? NULL
+                                        : ft->results()->copy());
+      Function_type* mft = Type::make_function_type(NULL, mparams, mresults,
+                                                   ft->location());
+
       mfields[i].name = Gogo::unpack_hidden_name(p->name());
       mfields[i].btype = (use_placeholder
-                         ? p->type()->get_backend_placeholder(gogo)
-                         : p->type()->get_backend(gogo));
+                         ? mft->get_backend_placeholder(gogo)
+                         : mft->get_backend(gogo));
       mfields[i].location = loc;
       // Sanity check: the names should be sorted.
       go_assert(p->name() > last_name);
@@ -7040,7 +7100,7 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name)
            mvals->push_back(Expression::make_nil(bloc));
          else
            {
-             s = Gogo::hidden_name_prefix(pm->name());
+             s = Gogo::hidden_name_pkgpath(pm->name());
              e = Expression::make_string(s, bloc);
              mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
            }
@@ -7089,11 +7149,15 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
            {
              if (!Gogo::is_hidden_name(p->name()))
                ret->append(p->name());
+             else if (gogo->pkgpath_from_option())
+               ret->append(p->name().substr(1));
              else
                {
-                 // This matches what the gc compiler does.
-                 std::string prefix = Gogo::hidden_name_prefix(p->name());
-                 ret->append(prefix.substr(prefix.find('.') + 1));
+                 // If no -fgo-pkgpath option, backward compatibility
+                 // for how this used to work before -fgo-pkgpath was
+                 // introduced.
+                 std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
+                 ret->append(pkgpath.substr(pkgpath.find('.') + 1));
                  ret->push_back('.');
                  ret->append(Gogo::unpack_hidden_name(p->name()));
                }
@@ -7158,7 +7222,7 @@ Interface_type::do_export(Export* exp) const
        {
          if (pm->name().empty())
            {
-             exp->write_c_string("$ ");
+             exp->write_c_string("? ");
              exp->write_type(pm->type());
            }
          else
@@ -7182,6 +7246,8 @@ Interface_type::do_export(Export* exp) const
                        first = false;
                      else
                        exp->write_c_string(", ");
+                     exp->write_name(pp->name());
+                     exp->write_c_string(" ");
                      if (!is_varargs || pp + 1 != parameters->end())
                        exp->write_type(pp->type());
                      else
@@ -7199,7 +7265,7 @@ Interface_type::do_export(Export* exp) const
              if (results != NULL)
                {
                  exp->write_c_string(" ");
-                 if (results->size() == 1)
+                 if (results->size() == 1 && results->begin()->name().empty())
                    exp->write_type(results->begin()->type());
                  else
                    {
@@ -7214,6 +7280,8 @@ Interface_type::do_export(Export* exp) const
                            first = false;
                          else
                            exp->write_c_string(", ");
+                         exp->write_name(p->name());
+                         exp->write_c_string(" ");
                          exp->write_type(p->type());
                        }
                      exp->write_c_string(")");
@@ -7240,7 +7308,7 @@ Interface_type::do_import(Import* imp)
     {
       std::string name = imp->read_identifier();
 
-      if (name == "$")
+      if (name == "?")
        {
          imp->require_c_string(" ");
          Type* t = imp->read_type();
@@ -7260,6 +7328,9 @@ Interface_type::do_import(Import* imp)
          parameters = new Typed_identifier_list;
          while (true)
            {
+             std::string name = imp->read_name();
+             imp->require_c_string(" ");
+
              if (imp->match_c_string("..."))
                {
                  imp->advance(3);
@@ -7269,8 +7340,8 @@ Interface_type::do_import(Import* imp)
              Type* ptype = imp->read_type();
              if (is_varargs)
                ptype = Type::make_array_type(ptype, NULL);
-             parameters->push_back(Typed_identifier(Import::import_marker,
-                                                    ptype, imp->location()));
+             parameters->push_back(Typed_identifier(name, ptype,
+                                                    imp->location()));
              if (imp->peek_char() != ',')
                break;
              go_assert(!is_varargs);
@@ -7289,17 +7360,18 @@ Interface_type::do_import(Import* imp)
          if (imp->peek_char() != '(')
            {
              Type* rtype = imp->read_type();
-             results->push_back(Typed_identifier(Import::import_marker,
-                                                 rtype, imp->location()));
+             results->push_back(Typed_identifier("", rtype, imp->location()));
            }
          else
            {
              imp->advance(1);
              while (true)
                {
+                 std::string name = imp->read_name();
+                 imp->require_c_string(" ");
                  Type* rtype = imp->read_type();
-                 results->push_back(Typed_identifier(Import::import_marker,
-                                                     rtype, imp->location()));
+                 results->push_back(Typed_identifier(name, rtype,
+                                                     imp->location()));
                  if (imp->peek_char() != ',')
                    break;
                  imp->require_c_string(", ");
@@ -7831,6 +7903,10 @@ Find_type_use::type(Type* type)
 bool
 Named_type::do_verify()
 {
+  if (this->is_verified_)
+    return true;
+  this->is_verified_ = true;
+
   Find_type_use find(this);
   Type::traverse(this->type_, &find);
   if (find.found())
@@ -7848,7 +7924,6 @@ Named_type::do_verify()
   if (this->local_methods_ != NULL)
     {
       Struct_type* st = this->type_->struct_type();
-      bool found_dup = false;
       if (st != NULL)
        {
          for (Bindings::const_declarations_iterator p =
@@ -7862,12 +7937,9 @@ Named_type::do_verify()
                  error_at(p->second->location(),
                           "method %qs redeclares struct field name",
                           Gogo::message_name(name).c_str());
-                 found_dup = true;
                }
            }
        }
-      if (found_dup)
-       return false;
     }
 
   return true;
@@ -7919,20 +7991,14 @@ Named_type::do_hash_for_method(Gogo* gogo) const
   // where we are going to be comparing named types for equality.  In
   // other cases, which are cases where the runtime is going to
   // compare hash codes to see if the types are the same, we need to
-  // include the package prefix and name in the hash.
+  // include the pkgpath in the hash.
   if (gogo != NULL && !Gogo::is_hidden_name(name) && !this->is_builtin())
     {
       const Package* package = this->named_object()->package();
       if (package == NULL)
-       {
-         ret = Type::hash_string(gogo->unique_prefix(), ret);
-         ret = Type::hash_string(gogo->package_name(), ret);
-       }
+       ret = Type::hash_string(gogo->pkgpath(), ret);
       else
-       {
-         ret = Type::hash_string(package->unique_prefix(), ret);
-         ret = Type::hash_string(package->name(), ret);
-       }
+       ret = Type::hash_string(package->pkgpath(), ret);
     }
 
   return ret;
@@ -7951,6 +8017,11 @@ Named_type::convert(Gogo* gogo)
 
   this->create_placeholder(gogo);
 
+  // If we are called to turn unsafe.Sizeof into a constant, we may
+  // not have verified the type yet.  We have to make sure it is
+  // verified, since that sets the list of dependencies.
+  this->verify();
+
   // Convert all the dependencies.  If they refer indirectly back to
   // this type, they will pick up the intermediate tree we just
   // created.
@@ -8304,17 +8375,38 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
     }
   if (!this->is_builtin())
     {
+      // We handle -fgo-prefix and -fgo-pkgpath differently here for
+      // compatibility with how the compiler worked before
+      // -fgo-pkgpath was introduced.  When -fgo-pkgpath is specified,
+      // we use it to make a unique reflection string, so that the
+      // type canonicalization in the reflect package will work.  In
+      // order to be compatible with the gc compiler, we put tabs into
+      // the package path, so that the reflect methods can discard it.
       const Package* package = this->named_object_->package();
-      if (package != NULL)
-       ret->append(package->name());
-      else
-       ret->append(gogo->package_name());
+      if (gogo->pkgpath_from_option())
+       {
+         ret->push_back('\t');
+         ret->append(package != NULL
+                     ? package->pkgpath_symbol()
+                     : gogo->pkgpath_symbol());
+         ret->push_back('\t');
+       }
+      ret->append(package != NULL
+                 ? package->package_name()
+                 : gogo->package_name());
       ret->push_back('.');
     }
   if (this->in_function_ != NULL)
     {
       ret->append(Gogo::unpack_hidden_name(this->in_function_->name()));
       ret->push_back('$');
+      if (this->in_function_index_ > 0)
+       {
+         char buf[30];
+         snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+         ret->append(buf);
+         ret->push_back('$');
+       }
     }
   ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
 }
@@ -8335,20 +8427,22 @@ Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
     go_assert(this->in_function_ == NULL);
   else
     {
-      const std::string& unique_prefix(no->package() == NULL
-                                      ? gogo->unique_prefix()
-                                      : no->package()->unique_prefix());
-      const std::string& package_name(no->package() == NULL
-                                     ? gogo->package_name()
-                                     : no->package()->name());
-      name = unique_prefix;
-      name.append(1, '.');
-      name.append(package_name);
+      const std::string& pkgpath(no->package() == NULL
+                                ? gogo->pkgpath_symbol()
+                                : no->package()->pkgpath_symbol());
+      name = pkgpath;
       name.append(1, '.');
       if (this->in_function_ != NULL)
        {
          name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
          name.append(1, '$');
+         if (this->in_function_index_ > 0)
+           {
+             char buf[30];
+             snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+             name.append(buf);
+             name.append(1, '$');
+           }
        }
     }
   name.append(Gogo::unpack_hidden_name(no->name()));
@@ -8950,7 +9044,7 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
                 Gogo::message_name(name).c_str(), ambig1.c_str(),
                 ambig2.c_str());
       else if (found_pointer_method)
-       error_at(location, "method requires a pointer");
+       error_at(location, "method requires a pointer receiver");
       else if (nt == NULL && st == NULL && it == NULL)
        error_at(location,
                 ("reference to field %qs in object which "
@@ -9467,9 +9561,9 @@ Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
       const Named_object* no = this->named_object();
       std::string name;
       if (no->package() == NULL)
-       name = gogo->package_name();
+       name = gogo->pkgpath_symbol();
       else
-       name = no->package()->name();
+       name = no->package()->pkgpath_symbol();
       name += '.';
       name += Gogo::unpack_hidden_name(no->name());
       char buf[20];