1// run
2
3//go:build !nacl && !js && !wasip1 && !gccgo
4
5// Copyright 2019 The Go Authors. All rights reserved.
6// Use of this source code is governed by a BSD-style
7// license that can be found in the LICENSE file.
8
9// Test that the linker permits long call sequences.
10package main
11
12import (
13	"bytes"
14	"fmt"
15	"io/ioutil"
16	"os"
17	"os/exec"
18	"path/filepath"
19	"strconv"
20)
21
22const start = `
23package main
24
25func main() {
26	println(f0() + 1)
27}
28`
29
30const fn = `
31//go:noinline
32func f%d() int {
33	return f%d() + 1
34}`
35
36const fnlast = `
37//go:noinline
38func f%d() int {
39	return 0
40}
41`
42
43const count = 400
44
45func main() {
46	if err := test(); err != nil {
47		fmt.Fprintln(os.Stderr, err)
48		os.Exit(1)
49	}
50}
51
52func test() error {
53	var buf bytes.Buffer
54	buf.WriteString(start)
55	for i := 0; i < count; i++ {
56		fmt.Fprintf(&buf, fn, i, i + 1)
57	}
58	fmt.Fprintf(&buf, fnlast, count)
59
60	dir, err := ioutil.TempDir("", "issue33555")
61	if err != nil {
62		return err
63	}
64	defer os.RemoveAll(dir)
65
66	fn := filepath.Join(dir, "x.go")
67	if err := ioutil.WriteFile(fn, buf.Bytes(), 0644); err != nil {
68		return err
69	}
70
71	out, err := exec.Command("go", "run", fn).CombinedOutput()
72	if err != nil {
73		return err
74	}
75
76	want := strconv.Itoa(count + 1)
77	if got := string(bytes.TrimSpace(out)); got != want {
78		return fmt.Errorf("got %q want %q", got, want)
79	}
80
81	return nil
82}
83