diff --git a/doc/go_spec.html b/doc/go_spec.html index e397d0aea0368419bc92aaf0a1ed5de31c44af4b..0e52d4d230ce5c0285bb2f8c019100941572cb8e 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,5 +1,5 @@ <!-- title The Go Programming Language Specification --> -<!-- subtitle Version of November 13, 2011 --> +<!-- subtitle Version of November 14, 2011 --> <!-- TODO @@ -1367,15 +1367,6 @@ by a value of type <code>T</code>. </li> </ul> -<p> -If <code>T</code> is a struct type with non-<a href="#Exported_identifiers">exported</a> -fields, the assignment must be in the same package in which <code>T</code> is declared, -or <code>x</code> must be the receiver of a method call. -In other words, a struct value can be assigned to a struct variable only if -every field of the struct may be legally assigned individually by the program, -or if the assignment is initializing the receiver of a method of the struct type. -</p> - <p> Any value may be assigned to the <a href="#Blank_identifier">blank identifier</a>. </p> diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index e21620f4553067ff3470578dbe4a0cfb36b695f7..a473c2fb504184acb77a5b9f2060330692c0be9c 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1234,7 +1234,6 @@ void walkswitch(Node *sw); /* * typecheck.c */ -int exportassignok(Type *t, char *desc); int islvalue(Node *n); Node* typecheck(Node **np, int top); void typechecklist(NodeList *l, int top); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 0df34c1a4fb6ecafe41ea541da91c8ed38466245..913ea22d3049992eabe6e0430812eb8c40a1afe3 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -1018,9 +1018,6 @@ eqtypenoname(Type *t1, Type *t2) // Is type src assignment compatible to type dst? // If so, return op code to use in conversion. // If not, return 0. -// -// It is the caller's responsibility to call exportassignok -// to check for assignments to other packages' unexported fields, int assignop(Type *src, Type *dst, char **why) { @@ -1225,7 +1222,6 @@ assignconv(Node *n, Type *t, char *context) if(t->etype == TBLANK) return n; - exportassignok(n->type, context); if(eqtype(n->type, t)) return n; diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index aaf836f8239c45997b5bc3c8edb55914520cff33..5b667553fa23a5b4324a569182d937e3344978a8 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -1045,8 +1045,6 @@ reswitch: yyerror("first argument to append must be slice; have %lT", t); goto error; } - if(!exportassignok(t->type, "append")) - goto error; if(n->isddd) { if(args->next == nil) { @@ -1114,8 +1112,6 @@ reswitch: yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type); goto error; } - if(!exportassignok(n->left->type->type, "copy")) - goto error; goto ret; case OCONV: @@ -1731,7 +1727,6 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * for(tl=tstruct->type; tl; tl=tl->down) { if(tl->isddd) { for(; tn; tn=tn->down) { - exportassignok(tn->type, desc); if(assignop(tn->type, tl->type->type, &why) == 0) { if(call != N) yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why); @@ -1743,7 +1738,6 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * } if(tn == T) goto notenough; - exportassignok(tn->type, desc); if(assignop(tn->type, tl->type, &why) == 0) { if(call != N) yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why); @@ -1815,66 +1809,6 @@ toomany: goto out; } -/* - * do the export rules allow writing to this type? - * cannot be implicitly assigning to any type with - * an unavailable field. - */ -int -exportassignok(Type *t, char *desc) -{ - Type *f; - Sym *s; - - if(t == T) - return 1; - if(t->trecur) - return 1; - t->trecur = 1; - - switch(t->etype) { - default: - // most types can't contain others; they're all fine. - break; - case TSTRUCT: - for(f=t->type; f; f=f->down) { - if(f->etype != TFIELD) - fatal("structas: not field"); - s = f->sym; - // s == nil doesn't happen for embedded fields (they get the type symbol). - // it only happens for fields in a ... struct. - if(s != nil && !exportname(s->name) && s->pkg != localpkg) { - char *prefix; - - prefix = ""; - if(desc != nil) - prefix = " in "; - else - desc = ""; - yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc); - goto no; - } - if(!exportassignok(f->type, desc)) - goto no; - } - break; - - case TARRAY: - if(t->bound < 0) // slices are pointers; that's fine - break; - if(!exportassignok(t->type, desc)) - goto no; - break; - } - t->trecur = 0; - return 1; - -no: - t->trecur = 0; - return 0; -} - - /* * type check composite */ @@ -2310,8 +2244,6 @@ typecheckas(Node *n) if(n->right && n->right->type != T) { if(n->left->type != T) n->right = assignconv(n->right, n->left->type, "assignment"); - else if(!isblank(n->left)) - exportassignok(n->right->type, "assignment"); } if(n->left->defn == n && n->left->ntype == N) { defaultlit(&n->right, T); @@ -2335,7 +2267,6 @@ checkassignto(Type *src, Node *dst) yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why); return; } - exportassignok(dst->type, "multiple assignment"); } static void diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go index 15d66813a207ceb10a9fccaba52acabf5c167b90..fc64301484cfdb9d8cb5b9aca02bef966c68de06 100644 --- a/src/pkg/os/file_plan9.go +++ b/src/pkg/os/file_plan9.go @@ -11,6 +11,14 @@ import ( // File represents an open file descriptor. type File struct { + *file +} + +// file is the real representation of *File. +// The extra level of indirection ensures that no clients of os +// can overwrite this data, which could cause the finalizer +// to close the wrong file descriptor. +type file struct { fd int name string dirinfo *dirInfo // nil unless directory being read @@ -29,8 +37,8 @@ func NewFile(fd int, name string) *File { if fd < 0 { return nil } - f := &File{fd: fd, name: name} - runtime.SetFinalizer(f, (*File).Close) + f := &File{&file{fd: fd, name: name}} + runtime.SetFinalizer(f.file, (*file).close) return f } @@ -110,6 +118,10 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) { // Close closes the File, rendering it unusable for I/O. // It returns an error, if any. func (file *File) Close() error { + return file.file.close() +} + +func (file *file) close() error { if file == nil || file.fd < 0 { return Ebadfd } diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go index d8fcb22ae1be955ef4af6abdd4e8f888faf85193..f3e0d1f9bec716db6bc69a5f7f39a237e9cf6398 100644 --- a/src/pkg/os/file_unix.go +++ b/src/pkg/os/file_unix.go @@ -13,6 +13,14 @@ import ( // File represents an open file descriptor. type File struct { + *file +} + +// file is the real representation of *File. +// The extra level of indirection ensures that no clients of os +// can overwrite this data, which could cause the finalizer +// to close the wrong file descriptor. +type file struct { fd int name string dirinfo *dirInfo // nil unless directory being read @@ -32,8 +40,8 @@ func NewFile(fd int, name string) *File { if fd < 0 { return nil } - f := &File{fd: fd, name: name} - runtime.SetFinalizer(f, (*File).Close) + f := &File{&file{fd: fd, name: name}} + runtime.SetFinalizer(f.file, (*file).close) return f } @@ -71,6 +79,10 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) { // Close closes the File, rendering it unusable for I/O. // It returns an error, if any. func (file *File) Close() error { + return file.file.close() +} + +func (file *file) close() error { if file == nil || file.fd < 0 { return EINVAL } diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go index fef868c68e62361ebae392cf5670019f7ff44dd3..5b098880f4cebb71534cfcb1e49e66eb8686b8e8 100644 --- a/src/pkg/os/file_windows.go +++ b/src/pkg/os/file_windows.go @@ -13,6 +13,14 @@ import ( // File represents an open file descriptor. type File struct { + *file +} + +// file is the real representation of *File. +// The extra level of indirection ensures that no clients of os +// can overwrite this data, which could cause the finalizer +// to close the wrong file descriptor. +type file struct { fd syscall.Handle name string dirinfo *dirInfo // nil unless directory being read @@ -33,8 +41,8 @@ func NewFile(fd syscall.Handle, name string) *File { if fd < 0 { return nil } - f := &File{fd: fd, name: name} - runtime.SetFinalizer(f, (*File).Close) + f := &File{&file{fd: fd, name: name}} + runtime.SetFinalizer(f.file, (*file).close) return f } @@ -99,6 +107,10 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) { // Close closes the File, rendering it unusable for I/O. // It returns an error, if any. func (file *File) Close() error { + return file.file.close() +} + +func (file *file) close() error { if file == nil || file.fd < 0 { return EINVAL } diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go index 2d46c89948fe9c3e25633399c68769ad8bdc8ee6..4fc02743c6e717b19903ee99867f7d7cafba375b 100644 --- a/src/pkg/sync/mutex.go +++ b/src/pkg/sync/mutex.go @@ -6,6 +6,8 @@ // exclusion locks. Other than the Once and WaitGroup types, most are intended // for use by low-level library routines. Higher-level synchronization is // better done via channels and communication. +// +// Values containing the types defined in this package should not be copied. package sync import ( diff --git a/test/assign.go b/test/assign.go index 59471388c069531a119183abcba147644194ec1d..2192f9ede0884fce55a3426702aa911b2d7aa285 100644 --- a/test/assign.go +++ b/test/assign.go @@ -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 - } + } } diff --git a/test/fixedbugs/bug226.dir/x.go b/test/fixedbugs/bug226.dir/x.go deleted file mode 100644 index 64d7a29e7e134db4e216885fb28d31255fe6399e..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug226.dir/x.go +++ /dev/null @@ -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() diff --git a/test/fixedbugs/bug226.dir/y.go b/test/fixedbugs/bug226.dir/y.go deleted file mode 100644 index c66d592b7c01166418656a060180705c9620c02a..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug226.dir/y.go +++ /dev/null @@ -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; -} diff --git a/test/fixedbugs/bug226.go b/test/fixedbugs/bug226.go deleted file mode 100644 index 5457a64bc11fcf657e49eb193dc107a4b1d7141a..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug226.go +++ /dev/null @@ -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 diff --git a/test/fixedbugs/bug310.go b/test/fixedbugs/bug310.go deleted file mode 100644 index 191f3ed2b4eef6ecf4e8058ec24ab2a903805c42..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug310.go +++ /dev/null @@ -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" -} diff --git a/test/fixedbugs/bug359.go b/test/fixedbugs/bug359.go deleted file mode 100644 index 3701499ed20276d98e8f0add47b76c2ff0e33a2e..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug359.go +++ /dev/null @@ -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" -} diff --git a/test/fixedbugs/bug378.go b/test/fixedbugs/bug378.go deleted file mode 100644 index 91975f2e931475f597f85369a74c02611083d376..0000000000000000000000000000000000000000 --- a/test/fixedbugs/bug378.go +++ /dev/null @@ -1,27 +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 1387 -package foo - -import "bytes" - -func i() { - a := make([]bytes.Buffer, 1) - b := a[0] // ERROR "unexported field" -} - -func f() { - a := make([]bytes.Buffer, 1) - a = append(a, a...) // ERROR "unexported field" -} - - -func g() { - a := make([]bytes.Buffer, 1) - b := make([]bytes.Buffer, 1) - copy(b, a) // ERROR "unexported field" -}