From 6761b1eb1b9fdbe5e2b865d683167dd5af3e5c0b Mon Sep 17 00:00:00 2001
From: Robert Griesemer <gri@golang.org>
Date: Tue, 23 Oct 2018 14:45:09 -0700
Subject: [PATCH] cmd/compile: better errors for structs with conflicting
 fields and methods

If a field and method have the same name, mark the respective struct field
so that we don't report follow-on errors when the field/method is accessed.

Per suggestion of @mdempsky.

Fixes #28268.

Change-Id: Ia1ca4cdfe9bacd3739d1fd7ca5e014ca094245ee
Reviewed-on: https://go-review.googlesource.com/c/144259
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
---
 src/cmd/compile/internal/gc/dcl.go       |  5 ++--
 src/cmd/compile/internal/gc/typecheck.go |  2 +-
 test/fixedbugs/issue28268.go             | 30 ++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 3 deletions(-)
 create mode 100644 test/fixedbugs/issue28268.go

diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 516c33d0bb..22201e5044 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -863,7 +863,7 @@ func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sy
 // Add a method, declared as a function.
 // - msym is the method symbol
 // - t is function type (with receiver)
-// Returns a pointer to the existing or added Field.
+// Returns a pointer to the existing or added Field; or nil if there's an error.
 func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
 	if msym == nil {
 		Fatalf("no method symbol")
@@ -918,6 +918,7 @@ func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.F
 		for _, f := range mt.Fields().Slice() {
 			if f.Sym == msym {
 				yyerror("type %v has both field and method named %v", mt, msym)
+				f.SetBroke(true)
 				return nil
 			}
 		}
@@ -927,7 +928,7 @@ func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.F
 		if msym.Name != f.Sym.Name {
 			continue
 		}
-		// eqtype only checks that incoming and result parameters match,
+		// types.Identical only checks that incoming and result parameters match,
 		// so explicitly check that the receiver parameters match too.
 		if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
 			yyerror("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 0bbd89f05e..38d9fe078f 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -2443,7 +2443,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
 	}
 
 	if f1 != nil {
-		if dostrcmp > 1 {
+		if dostrcmp > 1 || f1.Broke() {
 			// Already in the process of diagnosing an error.
 			return f1
 		}
diff --git a/test/fixedbugs/issue28268.go b/test/fixedbugs/issue28268.go
new file mode 100644
index 0000000000..fdc6974d1c
--- /dev/null
+++ b/test/fixedbugs/issue28268.go
@@ -0,0 +1,30 @@
+// errorcheck
+
+// Copyright 2018 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.
+
+// Verify that follow-on errors due to conflicting
+// struct field and method names are suppressed.
+
+package p
+
+type T struct {
+	a, b, c int
+	E
+}
+
+type E struct{}
+
+func (T) b()  {} // ERROR "field and method named b"
+func (*T) E() {} // ERROR "field and method named E"
+
+func _() {
+	var x T
+	_ = x.a
+	_ = x.b // no follow-on error here
+	x.b()   // no follow-on error here
+	_ = x.c
+	_ = x.E // no follow-on error here
+	x.E()   // no follow-on error here
+}
-- 
2.30.9