OSDN Git Service

compiler: Better error message if method requires pointer receiver.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / types.cc
index 9e64a6a..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)
@@ -1295,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;
 }
 
@@ -1738,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";
@@ -1977,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));
@@ -2096,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));
     }
 
@@ -4272,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;
 
@@ -4668,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));
        }
@@ -4745,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
@@ -4836,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);
@@ -5450,6 +5493,11 @@ Array_type::get_length_tree(Gogo* gogo)
       mpz_t val;
       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");
@@ -6551,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.
@@ -6802,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;
@@ -7047,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));
            }
@@ -7096,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()));
                }
@@ -7846,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())
@@ -7930,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;
@@ -7962,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.
@@ -8315,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()));
 }
@@ -8346,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()));
@@ -8961,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 "
@@ -9478,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];