The Go language now permits copying hidden fields when passing a value to a method receiver. This patch implements that in gccgo. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r ea8e140e8fab go/expressions.cc --- a/go/expressions.cc Mon Mar 28 16:12:27 2011 -0700 +++ b/go/expressions.cc Mon Mar 28 16:51:23 2011 -0700 @@ -8558,10 +8558,11 @@ 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")); diff -r ea8e140e8fab go/types.cc --- a/go/types.cc Mon Mar 28 16:12:27 2011 -0700 +++ b/go/types.cc Mon Mar 28 16:51:23 2011 -0700 @@ -475,11 +475,14 @@ } // 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 @@ // 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 @@ 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. diff -r ea8e140e8fab go/types.h --- a/go/types.h Mon Mar 28 16:12:27 2011 -0700 +++ b/go/types.h Mon Mar 28 16:51:23 2011 -0700 @@ -521,6 +521,14 @@ 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 @@ : 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: gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go (revision 171576) +++ gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go (working copy) @@ -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"