view gcc/testsuite/go.go-torture/execute/names-1.go @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
line wrap: on
line source

// names-1 is a change detector for Go symbol names.  We don't want
// the name mangling to change silently.
package main

import (
	"bytes"
	"debug/elf"
	"debug/macho"
	"debug/pe"
	"fmt"
	"os"
	"runtime"
	"strings"
)

type Type int
type Alias = int

//go:noinline
func Function1(out *bytes.Buffer) int {
	var f2 func(int) int
	f1 := func(i int) int {
		if i == 0 {
			return 0
		}
		type NestedType struct { a int }
		t := NestedType{f2(i-1)}
		fmt.Fprint(out, t)
		return t.a
	}
	f2 = func(i int) int {
		if i == 0 {
			return 0
		}
		type NestedType struct { a int }
		t := NestedType{f1(i-1)}
		fmt.Fprint(out, t)
		return t.a
	}
	return f1(10) + f2(10)
}

//go:noinline
func Function2(out *bytes.Buffer) {
	{
		type T struct { b int }
		fmt.Fprint(out, T{1})
	}
	{
		type T struct { b int }
		fmt.Fprint(out, T{2})
	}
}

func (t Type) M(bool, int8, float32, complex64, string, func(), func(int16) (float64, complex128), *byte, struct { f int "tag #$%^&{}: 世界" }, []int32, [24]int64, map[uint8]uint16, chan uint32, <-chan uint64, chan <- uintptr, Type, Alias) {
}

//go:noinline
func Function3(out *bytes.Buffer) {
	fmt.Fprintf(out, "%T", Type(0))
}

func main() {
	if runtime.GOOS == "aix" {
		// Not supported on AIX until there is an externally
		// visible version of internal/xcoff.
		return
	}

	var b bytes.Buffer
	Function1(&b)
	Function2(&b)
	Function3(&b)
	_ = len(b.String())

	for _, n := range []string{"/proc/self/exe", os.Args[0]} {
		if f, err := os.Open(n); err == nil {
			checkFile(f)
			return
		}
	}
	fmt.Println("checksyms: could not find executable")
	fmt.Println("UNSUPPORTED: checksyms")
}

func checkFile(f *os.File) {
	var syms []string
	if ef, err := elf.NewFile(f); err == nil {
		esyms, err := ef.Symbols()
		if err != nil {
			panic(err)
		}
		for _, esym := range esyms {
			syms = append(syms, esym.Name)
		}
	} else if mf, err := macho.NewFile(f); err == nil {
		for _, msym := range mf.Symtab.Syms {
			syms = append(syms, msym.Name)
		}
	} else if pf, err := pe.NewFile(f); err == nil {
		for _, psym := range pf.Symbols {
			syms = append(syms, psym.Name)
		}
	} else {
		fmt.Println("checksyms: could not parse executable")
		fmt.Println("UNSUPPORTED: checksyms")
		return
	}
	checkSyms(syms)
}

var want = []string{
	"main.Function1",
	"main.Function1..f",
	"main.Function1..func1",
	"main.Function1..func1.main.NestedType..d",
	"main.Function1..func2",
	"main.Function1..func2.main.NestedType..d",
	"main.Function2",
	"main.Function2..f",
	"main.Function2.main.T..d",
	"main.Function2.main.T..i1..d",
	"main.Function3",
	"main.Function3..f",
	"main.Type..d",
	"main.Type.M",
	"main.main",
	"main.want",
	"type...1.1main.Type",  // Why is this here?
	"type...1main.Function1..func1.NestedType",
	"type...1main.Function1..func2.NestedType",
	"type...1main.Function2.T",
	"type...1main.Function2.T..i1",
	"type...1main.Type",
	"type..func.8.1main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
	"type..func.8bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
	"type..func.8main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
	"type..struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5",
}

func checkSyms(syms []string) {
	m := make(map[string]bool)
	for _, sym := range syms {
		if strings.Contains(sym, ".") {
			m[sym] = true
		}
	}

	ok := true
	for _, w := range want {
		if m[w] {
			delete(m, w)
		} else {
			fmt.Printf("checksyms: missing expected symbol %q\n", w)
			ok = false
		}
	}

	for sym := range m {
		if !strings.Contains(sym, "main") {
			continue
		}

		// Skip some symbols we may see but know are unimportant.
		if sym == "go-main.c" {
			continue
		}
		if strings.HasPrefix(sym, "runtime.") {
			continue
		}

		// We can see a lot of spurious .eq and .hash
		// functions for types defined in other packages.
		// This is a bug but skip them for now.
		if strings.Contains(sym, "..eq") || strings.Contains(sym, "..hash") {
			continue
		}

		// Skip closure types by skipping incomparable structs.
		// This may be a bug, not sure.
		if strings.Contains(sym, ".4x.5") {
			continue
		}

		// These functions may be inlined.
		if sym == "main.checkFile" || sym == "main.checkSyms" {
			continue
		}

		fmt.Printf("checksyms: found unexpected symbol %q\n", sym)
		ok = false
	}

	if !ok  {
		fmt.Println("FAIL: checksyms")
	}
}