Skip to content

Commit 4725c71

Browse files
committed
cmd/compile: copy blank parameter node when substituting function type
When a function type is copied (e.g. for substituting type parameters), we make copies of its parameter ir.Name nodes, so they are not shared with the old function type. But currently a blank (_) identifier is not copied but shared. The parameter node's frame offset is assigned (in ABI analysis) and then used in the concurrent backend. Shared node can cause a data race. Make a new blank parameter node to avoid sharing. (Unified IR does already not have this problem. This fixes non-unified-IR mode.) This seems to fix #55357. Change-Id: Ie27f08e5589ac7d5d3f0d0d5de1a21e4fd2765c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/443158 Reviewed-by: Keith Randall <[email protected]> Run-TryBot: Cherry Mui <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 8415ec8 commit 4725c71

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

src/cmd/compile/internal/test/race.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !compiler_bootstrap
6+
7+
package test
8+
9+
// The racecompile builder only builds packages, but does not build
10+
// or run tests. This is a non-test file to hold cases that (used
11+
// to) trigger compiler data races, so they will be exercised on
12+
// the racecompile builder.
13+
//
14+
// This package is not imported so functions here are not included
15+
// in the actual compiler.
16+
17+
// Issue 55357: data race when building multiple instantiations of
18+
// generic closures with _ parameters.
19+
func Issue55357() {
20+
type U struct {
21+
A int
22+
B string
23+
C string
24+
}
25+
var q T55357[U]
26+
q.Count()
27+
q.List()
28+
29+
type M struct {
30+
A int64
31+
B uint32
32+
C uint32
33+
}
34+
var q2 T55357[M]
35+
q2.Count()
36+
q2.List()
37+
}
38+
39+
type T55357[T any] struct{}
40+
41+
//go:noinline
42+
func (q *T55357[T]) do(w, v bool, fn func(bk []byte, v T) error) error {
43+
return nil
44+
}
45+
46+
func (q *T55357[T]) Count() (n int, rerr error) {
47+
err := q.do(false, false, func(kb []byte, _ T) error {
48+
n++
49+
return nil
50+
})
51+
return n, err
52+
}
53+
54+
func (q *T55357[T]) List() (list []T, rerr error) {
55+
var l []T
56+
err := q.do(false, true, func(_ []byte, v T) error {
57+
l = append(l, v)
58+
return nil
59+
})
60+
if err != nil {
61+
return nil, err
62+
}
63+
return l, nil
64+
}

src/cmd/compile/internal/typecheck/subr.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -1358,14 +1358,22 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
13581358
newfields[i].SetNointerface(true)
13591359
}
13601360
if f.Nname != nil && ts.Vars != nil {
1361-
v := ts.Vars[f.Nname.(*ir.Name)]
1361+
n := f.Nname.(*ir.Name)
1362+
v := ts.Vars[n]
13621363
if v != nil {
13631364
// This is the case where we are
13641365
// translating the type of the function we
13651366
// are substituting, so its dcls are in
13661367
// the subst.ts.vars table, and we want to
13671368
// change to reference the new dcl.
13681369
newfields[i].Nname = v
1370+
} else if ir.IsBlank(n) {
1371+
// Blank variable is not dcl list. Make a
1372+
// new one to not share.
1373+
m := ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
1374+
m.SetType(n.Type())
1375+
m.SetTypecheck(1)
1376+
newfields[i].Nname = m
13691377
} else {
13701378
// This is the case where we are
13711379
// translating the type of a function

0 commit comments

Comments
 (0)