Skip to content

Commit 1a8b4e0

Browse files
committed
cmd/compile: unique LinkString for renamed, embedded fields
Using type aliases, it's possible to create structs with embedded fields that have no corresponding type literal notation. However, we still need to generate a unique name for these types to use for linker symbols. This CL introduces a new "struct{ Name = Type }" syntax for use in LinkString formatting to represent these types. Reattempt at CL 372914, which was rolled back due to race-y LocalPkg.Lookup call that isn't safe for concurrency. Fixes #50190. Change-Id: I0b7fd81e1b0b3199a6afcffde96ade42495ad8d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/378434 Trust: Matthew Dempsky <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 6891d07 commit 1a8b4e0

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

src/cmd/compile/internal/types/fmt.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
631631
}
632632

633633
var name string
634+
nameSep := " "
634635
if verb != 'S' {
635636
s := f.Sym
636637

@@ -639,7 +640,47 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
639640
s = OrigSym(s)
640641
}
641642

642-
if s != nil && f.Embedded == 0 {
643+
// Using type aliases and embedded fields, it's possible to
644+
// construct types that can't be directly represented as a
645+
// type literal. For example, given "type Int = int" (#50190),
646+
// it would be incorrect to format "struct{ Int }" as either
647+
// "struct{ int }" or "struct{ Int int }", because those each
648+
// represent other, distinct types.
649+
//
650+
// So for the purpose of LinkString (i.e., fmtTypeID), we use
651+
// the non-standard syntax "struct{ Int = int }" to represent
652+
// embedded fields that have been renamed through the use of
653+
// type aliases.
654+
if f.Embedded != 0 {
655+
if mode == fmtTypeID {
656+
nameSep = " = "
657+
658+
// Compute tsym, the symbol that would normally be used as
659+
// the field name when embedding f.Type.
660+
// TODO(mdempsky): Check for other occurences of this logic
661+
// and deduplicate.
662+
typ := f.Type
663+
if typ.IsPtr() {
664+
base.Assertf(typ.Sym() == nil, "embedded pointer type has name: %L", typ)
665+
typ = typ.Elem()
666+
}
667+
tsym := typ.Sym()
668+
669+
// If the field name matches the embedded type's name, then
670+
// suppress printing of the field name. For example, format
671+
// "struct{ T }" as simply that instead of "struct{ T = T }".
672+
if tsym != nil && (s == tsym || IsExported(tsym.Name) && s.Name == tsym.Name) {
673+
s = nil
674+
}
675+
} else {
676+
// Suppress the field name for embedded fields for
677+
// non-LinkString formats, to match historical behavior.
678+
// TODO(mdempsky): Re-evaluate this.
679+
s = nil
680+
}
681+
}
682+
683+
if s != nil {
643684
if funarg != FunargNone {
644685
name = fmt.Sprint(f.Nname)
645686
} else if verb == 'L' {
@@ -658,7 +699,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
658699

659700
if name != "" {
660701
b.WriteString(name)
661-
b.WriteString(" ")
702+
b.WriteString(nameSep)
662703
}
663704

664705
if f.IsDDD() {

test/fixedbugs/issue50190.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// run
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
type Int = int
10+
11+
type A = struct{ int }
12+
type B = struct{ Int }
13+
14+
func main() {
15+
var x, y interface{} = A{}, B{}
16+
if x == y {
17+
panic("FAIL")
18+
}
19+
20+
{
21+
type C = int32
22+
x = struct{ C }{}
23+
}
24+
{
25+
type C = uint32
26+
y = struct{ C }{}
27+
}
28+
if x == y {
29+
panic("FAIL")
30+
}
31+
}

0 commit comments

Comments
 (0)