Permit copying hidden fields when passing method receiver.
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 28 Mar 2011 23:54:33 +0000 (23:54 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 28 Mar 2011 23:54:33 +0000 (23:54 +0000)
From-SVN: r171641

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h
gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go

index d1de2037b9e400d09bde2f4743890791dc6f46d2..791ab073a440717fc5a8a8bed79c08bf21873da0 100644 (file)
@@ -8558,10 +8558,11 @@ Call_expression::do_check_types(Gogo*)
       if (first_arg_type->points_to() == NULL)
        {
          // When passing a value, we need to check that we are
-         // permitted to copy it.
+         // permitted to copy it.  The language permits copying
+         // hidden fields for a method receiver.
          std::string reason;
-         if (!Type::are_assignable(fntype->receiver()->type(),
-                                   first_arg_type, &reason))
+         if (!Type::are_assignable_hidden_ok(fntype->receiver()->type(),
+                                             first_arg_type, &reason))
            {
              if (reason.empty())
                this->report_error(_("incompatible type for receiver"));
index 47dbc162c993b545f277c01f01564053beab4eec..0aef9ce4cc52b4f1f90d18635d69a12a206c2c62 100644 (file)
@@ -475,11 +475,14 @@ Type::are_compatible_for_binop(const Type* lhs, const Type* rhs)
 }
 
 // Return true if a value with type RHS may be assigned to a variable
-// with type LHS.  If REASON is not NULL, set *REASON to the reason
-// the types are not assignable.
+// with type LHS.  If CHECK_HIDDEN_FIELDS is true, check whether any
+// hidden fields are modified.  If REASON is not NULL, set *REASON to
+// the reason the types are not assignable.
 
 bool
-Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
+Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
+                                 bool check_hidden_fields,
+                                 std::string* reason)
 {
   // Do some checks first.  Make sure the types are defined.
   if (rhs != NULL
@@ -499,7 +502,9 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
 
       // All fields of a struct must be exported, or the assignment
       // must be in the same package.
-      if (rhs != NULL && rhs->forwarded()->forward_declaration_type() == NULL)
+      if (check_hidden_fields
+         && rhs != NULL
+         && rhs->forwarded()->forward_declaration_type() == NULL)
        {
          if (lhs->has_hidden_fields(NULL, reason)
              || rhs->has_hidden_fields(NULL, reason))
@@ -593,6 +598,25 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
   return false;
 }
 
+// Return true if a value with type RHS may be assigned to a variable
+// with type LHS.  If REASON is not NULL, set *REASON to the reason
+// the types are not assignable.
+
+bool
+Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
+{
+  return Type::are_assignable_check_hidden(lhs, rhs, true, reason);
+}
+
+// Like are_assignable but don't check for hidden fields.
+
+bool
+Type::are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
+                              std::string* reason)
+{
+  return Type::are_assignable_check_hidden(lhs, rhs, false, reason);
+}
+
 // Return true if a value with type RHS may be converted to type LHS.
 // If REASON is not NULL, set *REASON to the reason the types are not
 // convertible.
index 24f425bd8b99dba0cf4809dc33453cd6d4d273ed..3255d37ff9e58ec6014e7a93538397ba829d7b32 100644 (file)
@@ -521,6 +521,14 @@ class Type
   static bool
   are_assignable(const Type* lhs, const Type* rhs, std::string* reason);
 
+  // Return true if a value with type RHS is assignable to a variable
+  // with type LHS, ignoring any assignment of hidden fields
+  // (unexported fields of a type imported from another package).
+  // This is like the are_assignable method.
+  static bool
+  are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
+                          std::string* reason);
+
   // Return true if a value with type RHS may be converted to type
   // LHS.  If this returns false, and REASON is not NULL, it sets
   // *REASON.
@@ -1011,6 +1019,11 @@ class Type
            : NULL);
   }
 
+  // Support for are_assignable and are_assignable_hidden_ok.
+  static bool
+  are_assignable_check_hidden(const Type* lhs, const Type* rhs,
+                             bool check_hidden_fields, std::string* reason);
+
   // Get the hash and equality functions for a type.
   void
   type_functions(const char** hash_fn, const char** equal_fn) const;
index 01e8b7b4373da11bbaa59661b33ef2b0754fd01b..c66d592b7c01166418656a060180705c9620c02a 100644 (file)
@@ -15,7 +15,7 @@ func f() {
        _ = x.T{};
        _ = x.T{Y:2};
        
-       ok1.M();        // ERROR "assignment.*T"
+       ok1.M();
        bad1 := *ok;    // ERROR "assignment.*T"
        bad2 := ok1;    // ERROR "assignment.*T"
        *ok4 = ok1;     // ERROR "assignment.*T"