The Go language has changed to permit structs with hidden fields to be assigned. This patch implements that in the gccgo frontend. Because the change is somewhat experimental, I did not remove the old code, I merely stopped executing it. I will remove it later if the change sticks. This change meant that I had to add checks for assignments to hidden fields in struct composite literals. Those are still forbidden, and were previously picked up by the check on assignment. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 181938) +++ gcc/go/gofrontend/types.cc (working copy) @@ -605,7 +605,7 @@ Type::are_assignable_check_hidden(const bool Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) { - return Type::are_assignable_check_hidden(lhs, rhs, true, reason); + return Type::are_assignable_check_hidden(lhs, rhs, false, reason); } // Like are_assignable but don't check for hidden fields. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 181874) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -12817,7 +12817,22 @@ Composite_literal_expression::lower_stru Location location = this->location(); Struct_type* st = type->struct_type(); if (this->vals_ == NULL || !this->has_keys_) - return new Struct_construction_expression(type, this->vals_, location); + { + if (this->vals_ != NULL && !this->vals_->empty()) + { + std::string reason; + if (type->has_hidden_fields(NULL, &reason)) + { + if (reason.empty()) + error_at(this->location(), + "implicit assignment of hidden field"); + else + error_at(this->location(), "%s", reason.c_str()); + } + } + + return new Struct_construction_expression(type, this->vals_, location); + } size_t field_count = st->field_count(); std::vector<Expression*> vals(field_count); @@ -12964,6 +12979,26 @@ Composite_literal_expression::lower_stru return Expression::make_error(location); } + if (type->named_type() != NULL + && type->named_type()->named_object()->package() != NULL + && Gogo::is_hidden_name(sf->field_name())) + error_at(name_expr->location(), + "assignment of unexported field %qs in %qs literal", + Gogo::message_name(sf->field_name()).c_str(), + type->named_type()->message_name().c_str()); + else + { + std::string reason; + if (sf->type()->has_hidden_fields(NULL, &reason)) + { + if (reason.empty()) + error_at(name_expr->location(), + "implicit assignment of hidden field"); + else + error_at(name_expr->location(), "%s", reason.c_str()); + } + } + vals[index] = val; } Index: gcc/testsuite/go.test/test/assign.go =================================================================== --- gcc/testsuite/go.test/test/assign.go (revision 181963) +++ gcc/testsuite/go.test/test/assign.go (working copy) @@ -16,38 +16,38 @@ type T struct { func main() { { var x, y sync.Mutex - x = y // ERROR "assignment.*Mutex" + x = y // ok _ = x } { var x, y T - x = y // ERROR "assignment.*Mutex" + x = y // ok _ = x } { var x, y [2]sync.Mutex - x = y // ERROR "assignment.*Mutex" + x = y // ok _ = x } { var x, y [2]T - x = y // ERROR "assignment.*Mutex" + x = y // ok _ = x } { - x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex" + x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex" _ = x } { - x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex" + x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex" _ = x } { - x := &sync.Mutex{} // ok - var y sync.Mutex // ok - y = *x // ERROR "assignment.*Mutex" - *x = y // ERROR "assignment.*Mutex" + x := &sync.Mutex{} // ok + var y sync.Mutex // ok + y = *x // ok + *x = y // ok _ = x _ = y - } + } } Index: gcc/testsuite/go.test/test/fixedbugs/bug359.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug359.go (revision 181963) +++ gcc/testsuite/go.test/test/fixedbugs/bug359.go (working copy) @@ -1,26 +0,0 @@ -// errchk $G $D/$F.go - -// Copyright 2011 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. - -// issue 1910 -// error on wrong line - -package main - -import "container/list" - -type Painting struct { - fragments list.List // private -} - -func (p Painting) Foo() { - for e := p.fragments; e.Front() != nil; { // ERROR "unexported field|hidden field" - } -} - -// from comment 4 of issue 1910 -type Foo interface { - Run(a int) (a int) // ERROR "a redeclared|redefinition|previous" -} Index: gcc/testsuite/go.test/test/fixedbugs/bug310.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug310.go (revision 181963) +++ gcc/testsuite/go.test/test/fixedbugs/bug310.go (working copy) @@ -1,20 +0,0 @@ -// errchk $G $D/$F.go - -// Copyright 2010 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. - -package p - -import ( - "bytes" - "fmt" -) - -type t int - -func main() { - _ = t.bar // ERROR "no method" - var b bytes.Buffer - fmt.Print(b) // ERROR "implicit assignment" -} Index: gcc/testsuite/go.test/test/fixedbugs/bug226.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug226.go (revision 181963) +++ gcc/testsuite/go.test/test/fixedbugs/bug226.go (working copy) @@ -1,7 +0,0 @@ -// $G $D/$F.dir/x.go && errchk $G $D/$F.dir/y.go - -// Copyright 2009 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. - -ignored Index: gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go (revision 181963) +++ gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go (working copy) @@ -1,9 +0,0 @@ -// Copyright 2009 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. - -package x - -type T struct { x, Y int } - -func (t T) M() Index: gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go (revision 181963) +++ gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go (working copy) @@ -1,31 +0,0 @@ -// Copyright 2009 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. - -package y - -import "./x" - -func f() { - ok := new(x.T); - var ok1 x.T; - ok2 := &ok1; - ok3 := &x.T{}; - ok4 := &x.T{Y:2}; - _ = x.T{}; - _ = x.T{Y:2}; - - ok1.M(); - bad1 := *ok; // ERROR "assignment.*T" - bad2 := ok1; // ERROR "assignment.*T" - *ok4 = ok1; // ERROR "assignment.*T" - *ok4 = *ok2; // ERROR "assignment.*T" - ok1 = *ok4; // ERROR "assignment.*T" - _ = bad1; - _ = bad2; - _ = ok4; - _ = ok3; - _ = ok2; - _ = ok1; - _ = ok; -}