modernc.org/ccgo/v3@v3.16.14/lib/all_test.go (about)

     1  // Copyright 2020 The CCGO 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  package ccgo // import "modernc.org/ccgo/v3/lib"
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"context"
    11  	"encoding/hex"
    12  	"flag"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"os"
    17  	"os/exec"
    18  	"path"
    19  	"path/filepath"
    20  	"reflect"
    21  	"regexp"
    22  	"runtime"
    23  	"runtime/debug"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  	"sync"
    28  	"sync/atomic"
    29  	"testing"
    30  	"time"
    31  	"unsafe"
    32  
    33  	"github.com/dustin/go-humanize"
    34  	"github.com/pmezard/go-difflib/difflib"
    35  	"modernc.org/cc/v3"
    36  	"modernc.org/ccorpus"
    37  )
    38  
    39  func caller(s string, va ...interface{}) {
    40  	if s == "" {
    41  		s = strings.Repeat("%v ", len(va))
    42  	}
    43  	_, fn, fl, _ := runtime.Caller(2)
    44  	fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
    45  	fmt.Fprintf(os.Stderr, s, va...)
    46  	fmt.Fprintln(os.Stderr)
    47  	_, fn, fl, _ = runtime.Caller(1)
    48  	fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
    49  	fmt.Fprintln(os.Stderr)
    50  	os.Stderr.Sync()
    51  }
    52  
    53  func dbg(s string, va ...interface{}) {
    54  	if s == "" {
    55  		s = strings.Repeat("%v ", len(va))
    56  	}
    57  	_, fn, fl, _ := runtime.Caller(1)
    58  	fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
    59  	fmt.Fprintf(os.Stderr, s, va...)
    60  	fmt.Fprintln(os.Stderr)
    61  	os.Stderr.Sync()
    62  }
    63  
    64  func TODO(...interface{}) string { //TODOOK
    65  	_, fn, fl, _ := runtime.Caller(1)
    66  	return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK
    67  }
    68  
    69  func stack() string { return string(debug.Stack()) }
    70  
    71  func use(...interface{}) {}
    72  
    73  func init() {
    74  	use(caller, dbg, TODO, stack) //TODOOK
    75  }
    76  
    77  // ----------------------------------------------------------------------------
    78  
    79  const execTimeout = time.Minute * 30
    80  
    81  var (
    82  	fs = ccorpus.FileSystem()
    83  
    84  	oBlackBox   = flag.String("blackbox", "", "Record CSmith file to this file")
    85  	oCSmith     = flag.Duration("csmith", 15*time.Minute, "")
    86  	oCpp        = flag.Bool("cpp", false, "Amend compiler errors with preprocessor output")
    87  	oDebug      = flag.Bool("debug", false, "")
    88  	oFullPaths  = flag.Bool("full-paths", false, "")
    89  	oGCC        = flag.String("gcc", "", "")
    90  	oKeep       = flag.Bool("keep", false, "keep temp directories")
    91  	oKeepTmp    = flag.Bool("keep-tmp", false, "")
    92  	oO          = flag.Int("O", 1, "")
    93  	oRE         = flag.String("re", "", "")
    94  	oStackTrace = flag.Bool("trcstack", false, "")
    95  	oTrace      = flag.Bool("trc", false, "Print tested paths.")
    96  	oTraceF     = flag.Bool("trcf", false, "Print test file content")
    97  	oTraceO     = flag.Bool("trco", false, "Print test output")
    98  	oTrc2       = flag.Bool("trc2", false, "")
    99  	oXTags      = flag.String("xtags", "", "passed to go build of TestSQLite")
   100  	writeFailed = flag.Bool("write-failed", false, "Write all failed tests into a file called FAILED in the cwd, in the format of go maps for easy copy-pasting.")
   101  
   102  	gccDir    = filepath.FromSlash("testdata/gcc-9.1.0")
   103  	sqliteDir = filepath.FromSlash("testdata/sqlite-amalgamation-3420000")
   104  	tccDir    = filepath.FromSlash("testdata/tcc-0.9.27")
   105  
   106  	overlayDir           string
   107  	re                   *regexp.Regexp
   108  	systemCC             string
   109  	systemCCVersion      string
   110  	tempDir              string
   111  	testWD               string
   112  	initIncludePathsOnce sync.Once
   113  	includePaths         []string
   114  	predefined           string
   115  	sysIncludePaths      []string
   116  
   117  	keep = map[string]struct{}{
   118  		"go.mod": {},
   119  		"go.sum": {},
   120  	}
   121  
   122  	csmithDefaultArgs = strings.Join([]string{
   123  		"--bitfields",                     // --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default).
   124  		"--max-nested-struct-level", "10", // --max-nested-struct-level <num>: limit maximum nested level of structs to <num>(default 0). Only works in the exhaustive mode.
   125  		"--no-const-pointers",    // --const-pointers | --no-const-pointers: enable | disable const pointers (enabled by default).
   126  		"--no-consts",            // --consts | --no-consts: enable | disable const qualifier (enabled by default).
   127  		"--no-packed-struct",     // --packed-struct | --no-packed-struct: enable | disable packed structs by adding #pragma pack(1) before struct definition (disabled by default).
   128  		"--no-volatile-pointers", // --volatile-pointers | --no-volatile-pointers: enable | disable volatile pointers (enabled by default).
   129  		"--no-volatiles",         // --volatiles | --no-volatiles: enable | disable volatiles (enabled by default).
   130  		"--paranoid",             // --paranoid | --no-paranoid: enable | disable pointer-related assertions (disabled by default).
   131  	}, " ")
   132  )
   133  
   134  func TestMain(m *testing.M) {
   135  	var rc int
   136  	defer func() {
   137  		if err := recover(); err != nil {
   138  			rc = 1
   139  			fmt.Fprintf(os.Stderr, "PANIC: %v\n%s\n", err, debug.Stack())
   140  		}
   141  		os.Exit(rc)
   142  	}()
   143  
   144  	// fmt.Printf("test binary compiled for %s/%s\n", runtime.GOOS, runtime.GOARCH)
   145  	// fmt.Printf("temp dir: %s\n", os.TempDir()) //TODO-
   146  	// if s := os.Getenv("CCGO_CPP"); s != "" {
   147  	// 	fmt.Printf("CCGO_CPP=%s\n", os.Getenv("CCGO_CPP"))
   148  	// }
   149  
   150  	flag.BoolVar(&oTraceW, "trcw", false, "Print generator writes")
   151  	flag.BoolVar(&oTraceG, "trcg", false, "Print generator output")
   152  	flag.BoolVar(&oTracePin, "trcpin", false, "Print pinning")
   153  	flag.Parse()
   154  	if s := *oRE; s != "" {
   155  		re = regexp.MustCompile(s)
   156  	}
   157  	var err error
   158  	if testWD, err = os.Getwd(); err != nil {
   159  		panic("Cannot determine working dir: " + err.Error())
   160  	}
   161  	s := filepath.FromSlash("testdata/overlay")
   162  	if overlayDir, err = filepath.Abs(s); err != nil {
   163  		panic(err) //TODOOK
   164  	}
   165  	if *oGCC == "" {
   166  		var err error
   167  		initIncludePathsOnce.Do(func() { err = initIncludePaths("") })
   168  		if err != nil {
   169  			fmt.Println(err)
   170  			os.Exit(1)
   171  		}
   172  
   173  		if systemCC, err = exec.LookPath(env("CC", "gcc")); err != nil {
   174  			fmt.Println(err)
   175  			os.Exit(1)
   176  		}
   177  
   178  		fmt.Fprintf(os.Stderr, "CC=%s\n", systemCC)
   179  		out, err := exec.Command(systemCC, "--version").CombinedOutput()
   180  		if err == nil {
   181  			if a := strings.Split(string(out), "\n"); len(a) > 0 {
   182  				systemCCVersion = a[0]
   183  				fmt.Fprintf(os.Stderr, "%s\n", systemCCVersion)
   184  			}
   185  		}
   186  
   187  		os.Exit(testMain(m))
   188  	}
   189  
   190  	var args []string
   191  	for i, v := range os.Args {
   192  		if v == "-gcc" {
   193  			args = append(os.Args[:i], os.Args[i+2:]...)
   194  		}
   195  	}
   196  	a := strings.Split(*oGCC, ",")
   197  	for _, suffix := range a {
   198  		systemCC = fmt.Sprintf("gcc-%s", suffix)
   199  		systemCPP := fmt.Sprintf("cpp-%s", suffix)
   200  		var err error
   201  		if systemCC, err = exec.LookPath(systemCC); err != nil {
   202  			fmt.Fprintf(os.Stderr, "%s: %s\n", systemCC, err)
   203  			continue
   204  		}
   205  
   206  		if systemCPP, err = exec.LookPath(systemCPP); err != nil {
   207  			fmt.Fprintf(os.Stderr, "%s: %s\n", systemCPP, err)
   208  			continue
   209  		}
   210  
   211  		os.Setenv("CC", systemCC)
   212  		os.Setenv("CCGO_CPP", systemCPP)
   213  		cmd := exec.Command(args[0], args[1:]...)
   214  		cmd.Stdout = os.Stdout
   215  		cmd.Stderr = os.Stderr
   216  		if err := cmd.Run(); err != nil {
   217  			rc = 1
   218  		}
   219  	}
   220  	os.Exit(rc)
   221  }
   222  
   223  func initGoMod() error {
   224  	switch os.Getenv("GO111MODULE") {
   225  	case "off":
   226  		return nil
   227  	}
   228  
   229  	dummy := filepath.Join(tempDir, "dummy.go")
   230  	if err := ioutil.WriteFile(dummy, []byte(`
   231  package main
   232  
   233  import (
   234  	"modernc.org/libc"
   235  )
   236  
   237  var (
   238  	_ libc.TLS
   239  )
   240  func main() {}
   241  `), 0600); err != nil {
   242  		return err
   243  	}
   244  
   245  	wd, err := os.Getwd()
   246  	if err != nil {
   247  		return err
   248  	}
   249  
   250  	defer os.Chdir(wd)
   251  
   252  	if err := os.Chdir(tempDir); err != nil {
   253  		return err
   254  	}
   255  
   256  	if b, err := exec.Command("go", "mod", "init", "example.com/ccgotest").CombinedOutput(); err != nil {
   257  		return fmt.Errorf("go mod init: %s\nFAIL: %v", b, err)
   258  	}
   259  
   260  	if b, err := exec.Command("go", "mod", "tidy").CombinedOutput(); err != nil {
   261  		return fmt.Errorf("go mod tidy: %s\nFAIL: %v", b, err)
   262  	}
   263  
   264  	return nil
   265  }
   266  
   267  func testMain(m *testing.M) int {
   268  	var err error
   269  	tempDir, err = ioutil.TempDir("", "ccgo-test-")
   270  	if err != nil {
   271  		panic(err) //TODOOK
   272  	}
   273  
   274  	if err = initGoMod(); err != nil {
   275  		panic(err) //TODOOK
   276  	}
   277  
   278  	switch {
   279  	case *oKeepTmp:
   280  		fmt.Fprintf(os.Stderr, "keeping temporary directory %s\n", tempDir)
   281  	default:
   282  		defer os.RemoveAll(tempDir)
   283  	}
   284  
   285  	s := filepath.FromSlash("testdata/overlay")
   286  	if overlayDir, err = filepath.Abs(s); err != nil {
   287  		panic(err) //TODOOK
   288  	}
   289  
   290  	return m.Run()
   291  }
   292  
   293  func initIncludePaths(cpp string) error {
   294  	var err error
   295  	predefined, includePaths, sysIncludePaths, err = cc.HostConfig(cpp)
   296  	if err != nil {
   297  		return err
   298  	}
   299  
   300  	includePaths = append(includePaths, "@")
   301  	includePaths = append(includePaths, sysIncludePaths...)
   302  	return nil
   303  }
   304  
   305  type golden struct {
   306  	t *testing.T
   307  	f *os.File
   308  	w *bufio.Writer
   309  }
   310  
   311  func newGolden(t *testing.T, fn string) *golden {
   312  	if *oRE != "" {
   313  		return &golden{w: bufio.NewWriter(ioutil.Discard)}
   314  	}
   315  
   316  	f, err := os.Create(filepath.FromSlash(fn))
   317  	if err != nil { // Possibly R/O fs in a VM
   318  		base := filepath.Base(filepath.FromSlash(fn))
   319  		f, err = ioutil.TempFile("", base)
   320  		if err != nil {
   321  			t.Fatal(err)
   322  		}
   323  
   324  		t.Logf("writing results to %s\n", f.Name())
   325  	}
   326  
   327  	w := bufio.NewWriter(f)
   328  	return &golden{t, f, w}
   329  }
   330  
   331  func (g *golden) close() {
   332  	if g.f == nil {
   333  		return
   334  	}
   335  
   336  	if err := g.w.Flush(); err != nil {
   337  		g.t.Fatal(err)
   338  	}
   339  
   340  	if err := g.f.Close(); err != nil {
   341  		g.t.Fatal(err)
   342  	}
   343  }
   344  
   345  func h(v interface{}) string {
   346  	switch x := v.(type) {
   347  	case int:
   348  		return humanize.Comma(int64(x))
   349  	case int64:
   350  		return humanize.Comma(x)
   351  	case uint64:
   352  		return humanize.Comma(int64(x))
   353  	case float64:
   354  		return humanize.CommafWithDigits(x, 0)
   355  	default:
   356  		panic(fmt.Errorf("%T", x)) //TODOOK
   357  	}
   358  }
   359  
   360  type runResult struct {
   361  	ccTime    time.Duration
   362  	csmithSrc []byte
   363  	ccgoTime  time.Duration
   364  	err       error
   365  	name      string
   366  	out       []byte
   367  }
   368  
   369  type skipErr string
   370  
   371  func (e skipErr) Error() string { return "skipped: " + string(e) }
   372  
   373  type runTask struct {
   374  	args      []string
   375  	c         chan *runResult
   376  	cmd       string
   377  	csmithSrc []byte
   378  	opts      []string
   379  	src       string
   380  
   381  	ccCanFail       bool
   382  	doNotExec       bool
   383  	hasBinaryOutput bool
   384  }
   385  
   386  func (t *runTask) run() {
   387  	r := &runResult{name: t.src}
   388  	r.out, r.err, r.ccTime, r.ccgoTime = t.run0()
   389  	t.c <- r
   390  }
   391  
   392  func (t *runTask) run0() (_ []byte, err error, ccTime, ccgoTime time.Duration) {
   393  	const outLimit = 1 << 16
   394  	defer func() {
   395  		if e := recover(); e != nil {
   396  			switch {
   397  			case err == nil:
   398  				err = fmt.Errorf("PANIC: %v\n%s", e, debug.Stack())
   399  			default:
   400  				err = fmt.Errorf("%v\nPANIC: %v\n%s", err, e, debug.Stack())
   401  			}
   402  		}
   403  	}()
   404  
   405  	overlay := filepath.Join(overlayDir, t.src)
   406  	b, err := ioutil.ReadFile(overlay)
   407  	if err != nil {
   408  		if !os.IsNotExist(err) {
   409  			return nil, err, ccTime, ccgoTime
   410  		}
   411  
   412  		f, err := fs.Open(t.src)
   413  		if err != nil {
   414  			return nil, err, ccTime, ccgoTime
   415  		}
   416  
   417  		if b, err = ioutil.ReadAll(f); err != nil {
   418  			return nil, err, ccTime, ccgoTime
   419  		}
   420  
   421  		if err = f.Close(); err != nil {
   422  			return nil, err, ccTime, ccgoTime
   423  		}
   424  	}
   425  
   426  	overlay = filepath.Join(overlayDir, t.src+".expectrc")
   427  	b2, err := ioutil.ReadFile(overlay)
   428  	if err != nil {
   429  		f, err := fs.Open(t.src + ".expectrc")
   430  		if err == nil {
   431  			if b2, err = ioutil.ReadAll(f); err != nil {
   432  				return nil, err, ccTime, ccgoTime
   433  			}
   434  
   435  			if err = f.Close(); err != nil {
   436  				return nil, err, ccTime, ccgoTime
   437  			}
   438  		}
   439  	}
   440  	var expectRC int
   441  	if len(b2) != 0 {
   442  		s := strings.TrimSpace(string(b2))
   443  		n, err := strconv.ParseUint(s, 10, 32)
   444  		if err != nil {
   445  			return nil, err, ccTime, ccgoTime
   446  		}
   447  
   448  		expectRC = int(n)
   449  	}
   450  
   451  	baseName := filepath.Base(t.src)
   452  	if err := ioutil.WriteFile(baseName, b, 0600); err != nil {
   453  		return nil, err, ccTime, ccgoTime
   454  	}
   455  
   456  	args, err := getArgs(t.src)
   457  	if err != nil {
   458  		return nil, err, ccTime, ccgoTime
   459  	}
   460  
   461  	ccArgs := append([]string{"-w", "-lm"}, t.opts...)
   462  	ok := true
   463  	for _, v := range t.opts {
   464  		if strings.HasPrefix(v, "-O") {
   465  			ok = false
   466  			break
   467  		}
   468  	}
   469  	if ok && runtime.GOOS != "darwin" {
   470  		if o := *oO; o >= 0 {
   471  			ccArgs = append(ccArgs, fmt.Sprintf("-O%d", o))
   472  		}
   473  	}
   474  	if t.doNotExec {
   475  		ccArgs = append(ccArgs, "-c")
   476  	}
   477  	binary, err := makeCCBinary(baseName, t.doNotExec, ccArgs...)
   478  	if err != nil {
   479  		return nil, skipErr(err.Error()), ccTime, ccgoTime
   480  	}
   481  
   482  	const (
   483  		ccOut   = "cc.out"
   484  		ccgoOut = "ccgo.out"
   485  	)
   486  	var binaryBytes, binaryBytes2 int
   487  	var expected []byte
   488  	if !t.doNotExec {
   489  		ctx, cancel := context.WithTimeout(context.Background(), execTimeout)
   490  		defer cancel()
   491  		if t.cmd != "" {
   492  			binary = t.cmd
   493  		}
   494  		if len(t.args) != 0 {
   495  			args = t.args
   496  		}
   497  		t0 := time.Now()
   498  		if *oTrc2 {
   499  			fmt.Fprintf(os.Stderr, "%v: started CC binary for %s: %v %v\n", t0, baseName, binary, args)
   500  		}
   501  		switch {
   502  		case t.hasBinaryOutput:
   503  			binaryBytes, err = execute(ctx, binary, ccOut, args)
   504  			defer os.Remove(ccOut)
   505  		default:
   506  			if expected, err = testSingleCombinedoutput(ctx, exec.CommandContext(ctx, binary, args...)); len(expected) > outLimit {
   507  				panic(todo("", t.src, len(expected)))
   508  			}
   509  		}
   510  		ccTime = time.Since(t0)
   511  		if *oTrc2 {
   512  			switch {
   513  			case t.hasBinaryOutput:
   514  				fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes, err)
   515  			default:
   516  				fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, expected)
   517  			}
   518  		}
   519  		if err != nil {
   520  			switch {
   521  			case t.ccCanFail:
   522  				expected = nil
   523  				expectRC = 0
   524  			default:
   525  				rc := err.(*exec.ExitError).ProcessState.ExitCode()
   526  				if rc != expectRC {
   527  					return nil, skipErr(fmt.Sprintf("executing CC binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, expected)), ccTime, ccgoTime
   528  				}
   529  
   530  				err = nil
   531  			}
   532  		}
   533  
   534  		if *oTraceO {
   535  			switch {
   536  			case t.hasBinaryOutput:
   537  				fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", ccTime, args, binaryBytes)
   538  			default:
   539  				fmt.Fprintf(os.Stderr, "%v %q: %s\n", ccTime, args, expected)
   540  			}
   541  		}
   542  	}
   543  
   544  	if t.cmd == "" {
   545  		if err := os.Remove(binary); err != nil {
   546  			return nil, fmt.Errorf("removing %v: %v", binary, err), ccTime, ccgoTime
   547  		}
   548  	}
   549  
   550  	ccgoArgs := append([]string(nil), t.opts...)
   551  	ccgoArgs = append(ccgoArgs, "-D__ccgo_test__", "-export-fields", "F", "-ignore-unsupported-alignment")
   552  	if *oFullPaths {
   553  		ccgoArgs = append(ccgoArgs, "-full-paths-comments")
   554  	}
   555  	if binary, err = makeBinary(t.src, t.doNotExec, ccgoArgs...); err != nil {
   556  		return nil, err, ccTime, ccgoTime
   557  	}
   558  
   559  	var got []byte
   560  	if !t.doNotExec {
   561  		ctx, cancel := context.WithTimeout(context.Background(), execTimeout)
   562  		defer cancel()
   563  		if t.cmd != "" {
   564  			binary = t.cmd
   565  		}
   566  		if len(t.args) != 0 {
   567  			args = t.args
   568  		}
   569  		t0 := time.Now()
   570  		if *oTrc2 {
   571  			fmt.Fprintf(os.Stderr, "%v: started ccgo binary for %s: %v %v\n", t0, baseName, binary, args)
   572  		}
   573  		switch {
   574  		case t.hasBinaryOutput:
   575  			binaryBytes2, err = execute(ctx, binary, ccgoOut, args)
   576  			defer os.Remove(ccgoOut)
   577  		default:
   578  			if got, err = testSingleCombinedoutput(ctx, exec.CommandContext(ctx, binary, args...)); len(got) > outLimit {
   579  				panic(todo("", t.src, len(expected)))
   580  			}
   581  		}
   582  		ccgoTime = time.Since(t0)
   583  		if *oTrc2 {
   584  			switch {
   585  			case t.hasBinaryOutput:
   586  				fmt.Fprintf(os.Stderr, "%v: ccgo binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes2, err)
   587  			default:
   588  				fmt.Fprintf(os.Stderr, "%v: ccgo binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, got)
   589  			}
   590  		}
   591  		if err != nil {
   592  			rc := err.(*exec.ExitError).ProcessState.ExitCode()
   593  			if rc != expectRC {
   594  				return nil, fmt.Errorf("executing ccgo binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, got), ccTime, ccgoTime
   595  			}
   596  
   597  			err = nil
   598  		}
   599  
   600  		if *oTraceO {
   601  			switch {
   602  			case t.hasBinaryOutput:
   603  				fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", ccgoTime, args, binaryBytes2)
   604  			default:
   605  				fmt.Fprintf(os.Stderr, "%v %q: %s\n", ccgoTime, args, got)
   606  			}
   607  		}
   608  		switch {
   609  		case t.hasBinaryOutput:
   610  			if err := fileEqual(ccgoOut, ccOut); err != nil {
   611  				return nil, fmt.Errorf("binary output: %s", err), ccTime, ccgoTime
   612  			}
   613  		default:
   614  			got := string(got)
   615  			expected := string(expected)
   616  			got = strings.ReplaceAll(got, "\r", "")
   617  			got = lineTrim(strings.TrimSpace(got))
   618  			expected = strings.ReplaceAll(expected, "\r", "")
   619  			expected = lineTrim(strings.TrimSpace(expected))
   620  			if got != expected {
   621  				diff := difflib.UnifiedDiff{
   622  					A:        difflib.SplitLines(expected),
   623  					B:        difflib.SplitLines(got),
   624  					FromFile: "expected",
   625  					ToFile:   "got",
   626  					Context:  3,
   627  				}
   628  				text, _ := difflib.GetUnifiedDiffString(diff)
   629  				return nil, fmt.Errorf(
   630  					"%v: text output differs:\n%s\n---- x.c\ngot\n%s\nexp\n%s\ngot\n%s\nexp\n%s",
   631  					t.src, text,
   632  					hex.Dump([]byte(got)), hex.Dump([]byte(expected)),
   633  					got, expected,
   634  				), ccTime, ccgoTime
   635  			}
   636  		}
   637  	}
   638  	return got, err, ccTime, ccgoTime
   639  }
   640  
   641  func lineTrim(s string) string {
   642  	a := strings.Split(s, "\n")
   643  	for i, v := range a {
   644  		a[i] = strings.TrimSpace(v)
   645  	}
   646  	return strings.Join(a, "\n")
   647  }
   648  
   649  func fileEqual(g, e string) error {
   650  	fig, err := os.Stat(g)
   651  	if err != nil {
   652  		return err
   653  	}
   654  
   655  	fie, err := os.Stat(e)
   656  	if err != nil {
   657  		return err
   658  	}
   659  
   660  	if g, e := fig.Size(), fie.Size(); g != e {
   661  		return fmt.Errorf("files sizes differ, got %v, expected %v", g, e)
   662  	}
   663  
   664  	rem := fig.Size()
   665  	if rem == 0 {
   666  		return nil
   667  	}
   668  
   669  	var bg, be [4096]byte
   670  	fg, err := os.Open(g)
   671  	if err != nil {
   672  		return err
   673  	}
   674  
   675  	defer fg.Close()
   676  
   677  	fe, err := os.Open(e)
   678  	if err != nil {
   679  		return err
   680  	}
   681  
   682  	defer fe.Close()
   683  
   684  	for rem != 0 {
   685  		n, err := io.ReadFull(fg, bg[:])
   686  		if n == 0 {
   687  			if err == io.EOF {
   688  				err = nil
   689  			}
   690  			return err
   691  		}
   692  
   693  		n2, err := io.ReadFull(fe, be[:])
   694  		if n == 0 {
   695  			if err == io.EOF {
   696  				err = nil
   697  			}
   698  			return err
   699  		}
   700  
   701  		if n != n2 {
   702  			panic(todo("", n, n2))
   703  		}
   704  
   705  		if !bytes.Equal(bg[:n], be[:n]) {
   706  			return fmt.Errorf("files are different")
   707  		}
   708  
   709  		rem -= int64(n)
   710  	}
   711  	return nil
   712  }
   713  
   714  var ftoken uint32
   715  
   716  func newID() uint32 { return atomic.AddUint32(&ftoken, 1) }
   717  
   718  func makeBinary(src string, obj bool, args ...string) (executable string, err error) {
   719  	defer func() {
   720  		if err != nil {
   721  			if *oTrace {
   722  				fmt.Println(err)
   723  			}
   724  			err = cpp(*oCpp, args, err)
   725  			err = fmt.Errorf("%s: %v", src, err)
   726  		}
   727  	}()
   728  
   729  	pkg := "main"
   730  	if obj {
   731  		pkg = "foo"
   732  	}
   733  
   734  	main := fmt.Sprintf("main%d.go", newID())
   735  	src = filepath.Base(src)
   736  	if err := NewTask(append([]string{"ccgo", "-o", main, "-pkgname", pkg, "-nocapi", src}, args...), nil, nil).Main(); err != nil {
   737  		return "", err
   738  	}
   739  
   740  	if *oTraceF {
   741  		b, _ := ioutil.ReadFile(main)
   742  		fmt.Printf("\n----\n%s\n----\n", b)
   743  	}
   744  
   745  	executable = fmt.Sprintf("./%s%d", src[:len(src)-len(filepath.Ext(src))], newID())
   746  	var ext string
   747  	if runtime.GOOS == "windows" {
   748  		ext = ".exe"
   749  	}
   750  	executable += ext
   751  	os.Remove(executable)
   752  	var b []byte
   753  	switch {
   754  	case obj:
   755  		b, err = exec.Command("go", "build", main).CombinedOutput()
   756  	default:
   757  		b, err = exec.Command("go", "build", "-o", executable, main).CombinedOutput()
   758  	}
   759  	if err != nil {
   760  		err = fmt.Errorf("%s\n\tFAIL: %v", b, err)
   761  	}
   762  	return executable, err
   763  }
   764  
   765  type countingWriter struct {
   766  	written int
   767  	w       *bufio.Writer
   768  }
   769  
   770  func (c *countingWriter) Write(b []byte) (int, error) {
   771  	n, err := c.w.Write(b)
   772  	c.written += n
   773  	return n, err
   774  }
   775  
   776  var _ io.Writer = (*countingWriter)(nil)
   777  
   778  // err = execute(ctx, executable, args, ccOut)
   779  func execute(ctx context.Context, executable, out string, args []string) (n int, err error) {
   780  	cmd := exec.CommandContext(ctx, executable, args...)
   781  	f, err := os.Create(out)
   782  	if err != nil {
   783  		return 0, err
   784  	}
   785  
   786  	defer func() {
   787  		if e := f.Close(); e != nil && err == nil {
   788  			err = e
   789  		}
   790  	}()
   791  
   792  	w := &countingWriter{w: bufio.NewWriter(f)}
   793  
   794  	defer func() {
   795  		if e := w.w.Flush(); e != nil && err == nil {
   796  			err = e
   797  		}
   798  	}()
   799  
   800  	cmd.Stdout = w
   801  	err = testSingleRun(ctx, cmd)
   802  	return w.written, err
   803  }
   804  
   805  func makeCCBinary(src string, obj bool, args ...string) (executable string, err error) {
   806  	ext := ""
   807  	if obj {
   808  		ext = ".o"
   809  	}
   810  	src = filepath.Base(src)
   811  	executable = "./" + src[:len(src)-len(filepath.Ext(src))]
   812  	if runtime.GOOS == "windows" && !obj {
   813  		ext = ".exe"
   814  	}
   815  	executable += ext
   816  	os.Remove(executable)
   817  	b, err := exec.Command(systemCC, append([]string{"-o", executable, src}, args...)...).CombinedOutput()
   818  	if err != nil {
   819  		return "", fmt.Errorf("%v %v -o %v %v: system C compiler: %v\n%s", systemCC, args, executable, src, err, b)
   820  	}
   821  
   822  	return executable, nil
   823  }
   824  
   825  func getArgs(src string) (args []string, err error) {
   826  	src = src[:len(src)-len(filepath.Ext(src))] + ".arg"
   827  	overlay := filepath.Join(overlayDir, src)
   828  	b, err := ioutil.ReadFile(overlay)
   829  	if err != nil {
   830  		if !os.IsNotExist(err) {
   831  			return nil, err
   832  		}
   833  
   834  		f, err := fs.Open(src)
   835  		if err != nil {
   836  			return nil, nil
   837  		}
   838  
   839  		if b, err = ioutil.ReadAll(f); err != nil {
   840  			return nil, err
   841  		}
   842  
   843  		if err = f.Close(); err != nil {
   844  			return nil, err
   845  		}
   846  	}
   847  
   848  	a := strings.Split(strings.TrimSpace(string(b)), "\n")
   849  	for _, v := range a {
   850  		switch {
   851  		case strings.HasPrefix(v, "\"") || strings.HasPrefix(v, "`"):
   852  			w, err := strconv.Unquote(v)
   853  			if err != nil {
   854  				return nil, fmt.Errorf("%s: %v: %v", src, v, err)
   855  			}
   856  
   857  			args = append(args, w)
   858  		default:
   859  			args = append(args, v)
   860  		}
   861  	}
   862  	return args, nil
   863  }
   864  
   865  func TestTCC(t *testing.T) {
   866  	const root = "/tcc-0.9.27/tests/tests2"
   867  	g := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
   868  
   869  	defer g.close()
   870  
   871  	mustEmptyDir(t, tempDir, keep)
   872  	wd, err := os.Getwd()
   873  	if err != nil {
   874  		t.Fatal(err)
   875  	}
   876  
   877  	if err := os.Chdir(tempDir); err != nil {
   878  		t.Fatal(err)
   879  	}
   880  
   881  	defer func() {
   882  		if err := os.Chdir(wd); err != nil {
   883  			t.Fatal(err)
   884  		}
   885  	}()
   886  
   887  	needFiles(t, root, []string{
   888  		"18_include.h",
   889  		"95_bitfields.c",
   890  	})
   891  	blacklist := map[string]struct{}{
   892  		"60_errors_and_warnings.c":    {}, // no main
   893  		"73_arm64.c":                  {}, // does not work properly on any gcc tested (7-11)
   894  		"76_dollars_in_identifiers.c": {}, // `int $ = 10;` etc.
   895  		"77_push_pop_macro.c":         {}, // unsupported push/pop macro
   896  		"78_vla_label.c":              {}, //MAYBE
   897  		"79_vla_continue.c":           {}, //MAYBE
   898  		"80_flexarray.c":              {}, //MAYBE
   899  		"83_utf8_in_identifiers.c":    {}, // No support before gcc 10.
   900  		"85_asm-outside-function.c":   {}, // asm
   901  		"90_struct-init.c":            {}, // 90_struct-init.c:168:25: `...`: expected ]
   902  		"94_generic.c":                {}, // 94_generic.c:36:18: `int`: expected primary-expression
   903  		"95_bitfields.c":              {}, // Included from 95_bitfields_ms.c
   904  		"96_nodata_wanted.c":          {}, // no main
   905  		"98_al_ax_extend.c":           {}, // asm
   906  		"99_fastcall.c":               {}, // asm
   907  
   908  		"95_bitfields_ms.c": {}, //TODO
   909  	}
   910  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
   911  	case "linux/s390x":
   912  		blacklist["function forward decl 2.c"] = struct{}{} //TODO
   913  		blacklist["if bool eq int 0.c"] = struct{}{}        //TODO
   914  	case "freebsd/amd64":
   915  		blacklist["40_stdio.c"] = struct{}{} //TODO
   916  	case "netbsd/amd64":
   917  		blacklist["40_stdio.c"] = struct{}{} //TODO
   918  	}
   919  	var rq, res, ok int
   920  	limit := runtime.GOMAXPROCS(0)
   921  	limiter := make(chan struct{}, limit)
   922  	success := make([]string, 0, 0)
   923  	results := make(chan *runResult, limit)
   924  	failed := map[string]struct{}{}
   925  	err = walk(root, func(pth string, fi os.FileInfo) error {
   926  		if !strings.HasSuffix(pth, ".c") {
   927  			return nil
   928  		}
   929  
   930  		switch {
   931  		case re != nil:
   932  			if !re.MatchString(pth) {
   933  				return nil
   934  			}
   935  		default:
   936  			if _, ok := blacklist[filepath.Base(pth)]; ok {
   937  				return nil
   938  			}
   939  		}
   940  
   941  	more:
   942  		select {
   943  		case r := <-results:
   944  			res++
   945  			<-limiter
   946  			switch r.err.(type) {
   947  			case nil:
   948  				ok++
   949  				success = append(success, filepath.Base(r.name))
   950  				delete(failed, r.name)
   951  			case skipErr:
   952  				delete(failed, r.name)
   953  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
   954  			default:
   955  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
   956  			}
   957  			goto more
   958  		case limiter <- struct{}{}:
   959  			rq++
   960  			if *oTrace {
   961  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
   962  			}
   963  			failed[pth] = struct{}{}
   964  			go run(pth, false, false, false, results)
   965  		}
   966  		return nil
   967  	})
   968  	if err != nil {
   969  		t.Fatal(err)
   970  	}
   971  	for res != rq {
   972  		r := <-results
   973  		res++
   974  		<-limiter
   975  		switch r.err.(type) {
   976  		case nil:
   977  			ok++
   978  			success = append(success, filepath.Base(r.name))
   979  			delete(failed, r.name)
   980  		case skipErr:
   981  			delete(failed, r.name)
   982  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
   983  		default:
   984  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
   985  		}
   986  	}
   987  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
   988  	sort.Strings(success)
   989  	for _, fpath := range success {
   990  		g.w.Write([]byte(fpath))
   991  		g.w.Write([]byte{'\n'})
   992  	}
   993  	if len(failed) == 0 {
   994  		return
   995  	}
   996  
   997  	var a []string
   998  	for k := range failed {
   999  		a = append(a, k)
  1000  	}
  1001  	sort.Strings(a)
  1002  	for _, v := range a {
  1003  		t.Logf("FAIL %s", v)
  1004  	}
  1005  }
  1006  
  1007  func run(src string, binaryOut, ccCanFail, doNotExec bool, c chan *runResult, opts ...string) {
  1008  	(&runTask{
  1009  		c:               c,
  1010  		ccCanFail:       ccCanFail,
  1011  		doNotExec:       doNotExec,
  1012  		hasBinaryOutput: binaryOut,
  1013  		opts:            opts,
  1014  		src:             src,
  1015  	}).run()
  1016  }
  1017  
  1018  func walk(dir string, f func(pth string, fi os.FileInfo) error) error {
  1019  	if !strings.HasSuffix(dir, "/") {
  1020  		dir += "/"
  1021  	}
  1022  	root, err := fs.Open(dir)
  1023  	if err != nil {
  1024  		return err
  1025  	}
  1026  
  1027  	fi, err := root.Stat()
  1028  	if err != nil {
  1029  		return err
  1030  	}
  1031  
  1032  	if !fi.IsDir() {
  1033  		return fmt.Errorf("%s: not a directory", fi.Name())
  1034  	}
  1035  
  1036  	fis, err := root.Readdir(-1)
  1037  	if err != nil {
  1038  		return err
  1039  	}
  1040  
  1041  	for _, v := range fis {
  1042  		switch {
  1043  		case v.IsDir():
  1044  			if err = walk(v.Name(), f); err != nil {
  1045  				return err
  1046  			}
  1047  		default:
  1048  			if err = f(v.Name(), v); err != nil {
  1049  				return err
  1050  			}
  1051  		}
  1052  	}
  1053  	return nil
  1054  }
  1055  
  1056  func needFiles(t *testing.T, root string, a []string) {
  1057  	for _, v := range a {
  1058  		overlay := filepath.Join(overlayDir, filepath.FromSlash(root), v)
  1059  		b, err := ioutil.ReadFile(overlay)
  1060  		if err != nil {
  1061  			if !os.IsNotExist(err) {
  1062  				t.Fatal(err)
  1063  			}
  1064  
  1065  			f, err := fs.Open(path.Join(root, v))
  1066  			if err != nil {
  1067  				t.Fatal(err)
  1068  			}
  1069  
  1070  			if b, err = ioutil.ReadAll(f); err != nil {
  1071  				t.Fatal(err)
  1072  			}
  1073  
  1074  			if err = f.Close(); err != nil {
  1075  				t.Fatal(err)
  1076  			}
  1077  		}
  1078  		if dir, _ := filepath.Split(v); dir != "" {
  1079  			if err := os.MkdirAll(dir, 0700); err != nil {
  1080  				t.Fatal(err)
  1081  			}
  1082  		}
  1083  
  1084  		if err := ioutil.WriteFile(v, b, 0600); err != nil {
  1085  			t.Fatal(err)
  1086  		}
  1087  	}
  1088  }
  1089  
  1090  func mustEmptyDir(t *testing.T, s string, keep map[string]struct{}) {
  1091  	if err := emptyDir(s, keep); err != nil {
  1092  		t.Fatal(err)
  1093  	}
  1094  }
  1095  
  1096  func emptyDir(s string, keep map[string]struct{}) error {
  1097  	m, err := filepath.Glob(filepath.FromSlash(s + "/*"))
  1098  	if err != nil {
  1099  		return err
  1100  	}
  1101  
  1102  	for _, v := range m {
  1103  		fi, err := os.Stat(v)
  1104  		if err != nil {
  1105  			return err
  1106  		}
  1107  
  1108  		switch {
  1109  		case fi.IsDir():
  1110  			if err = os.RemoveAll(v); err != nil {
  1111  				return err
  1112  			}
  1113  		default:
  1114  			if _, ok := keep[filepath.Base(v)]; ok {
  1115  				break
  1116  			}
  1117  
  1118  			if err = os.Remove(v); err != nil {
  1119  				return err
  1120  			}
  1121  		}
  1122  	}
  1123  	return nil
  1124  }
  1125  
  1126  func cpp(enabled bool, args []string, err0 error) error {
  1127  	if !enabled {
  1128  		return err0
  1129  	}
  1130  
  1131  	args = append(args, "-E")
  1132  	var out bytes.Buffer
  1133  	if err := NewTask(args, &out, &out).Main(); err != nil {
  1134  		return fmt.Errorf("error while acquiring preprocessor output: %v\n%v", err, err0)
  1135  	}
  1136  
  1137  	return fmt.Errorf("preprocessor output:\n%s\n%v", out.Bytes(), err0)
  1138  }
  1139  
  1140  func trim(b []byte) (r []byte) {
  1141  	b = bytes.ReplaceAll(b, []byte{'\r'}, nil)
  1142  	b = bytes.TrimLeft(b, "\n")
  1143  	b = bytes.TrimRight(b, "\n")
  1144  	a := bytes.Split(b, []byte("\n"))
  1145  	for i, v := range a {
  1146  		a[i] = bytes.TrimRight(v, " ")
  1147  	}
  1148  	return bytes.Join(a, []byte("\n"))
  1149  }
  1150  
  1151  func noExt(s string) string {
  1152  	ext := filepath.Ext(s)
  1153  	if ext == "" {
  1154  		panic("internal error") //TODOOK
  1155  	}
  1156  	return s[:len(s)-len(ext)]
  1157  }
  1158  
  1159  func copyFile(src, dst string) error {
  1160  	b, err := ioutil.ReadFile(src)
  1161  	if err != nil {
  1162  		return err
  1163  	}
  1164  
  1165  	return ioutil.WriteFile(dst, b, 0660)
  1166  }
  1167  
  1168  func skipDir(path string) error {
  1169  	if strings.HasPrefix(filepath.Base(path), ".") {
  1170  		return filepath.SkipDir
  1171  	}
  1172  
  1173  	return nil
  1174  }
  1175  
  1176  func TestCAPI(t *testing.T) {
  1177  	task := NewTask(nil, nil, nil)
  1178  	pkgName, capi, err := task.capi("modernc.org/libc")
  1179  	if err != nil {
  1180  		t.Fatal(err)
  1181  	}
  1182  
  1183  	if _, ok := capi["printf"]; !ok {
  1184  		t.Fatal("default libc does not export printf")
  1185  	}
  1186  
  1187  	t.Log(pkgName, capi)
  1188  }
  1189  
  1190  const text = "abcd\nefgh\x00ijkl"
  1191  
  1192  var (
  1193  	text1 = text
  1194  	text2 = (*reflect.StringHeader)(unsafe.Pointer(&text1)).Data
  1195  )
  1196  
  1197  func TestText(t *testing.T) {
  1198  	p := text2
  1199  	var b []byte
  1200  	for i := 0; i < len(text); i++ {
  1201  		b = append(b, *(*byte)(unsafe.Pointer(p)))
  1202  		p++
  1203  	}
  1204  	if g, e := string(b), text; g != e {
  1205  		t.Fatalf("%q %q", g, e)
  1206  	}
  1207  }
  1208  
  1209  func TestMirBenchmarks(t *testing.T) {
  1210  	const root = "/github.com/vnmakarov/mir/c-benchmarks"
  1211  	g := newGolden(t, fmt.Sprintf("testdata/mir_c_benchmarks_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1212  
  1213  	defer g.close()
  1214  
  1215  	mustEmptyDir(t, tempDir, keep)
  1216  	wd, err := os.Getwd()
  1217  	if err != nil {
  1218  		t.Fatal(err)
  1219  	}
  1220  
  1221  	if err := os.Chdir(tempDir); err != nil {
  1222  		t.Fatal(err)
  1223  	}
  1224  
  1225  	defer func() {
  1226  		if err := os.Chdir(wd); err != nil {
  1227  			t.Fatal(err)
  1228  		}
  1229  	}()
  1230  
  1231  	needFiles(t, root, []string{
  1232  		"simple_hash.h",
  1233  	})
  1234  	blacklist := map[string]struct{}{
  1235  		"except.c": {}, // longjmp
  1236  	}
  1237  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  1238  	case "darwin/amd64":
  1239  		blacklist["method-call.c"] = struct{}{} //TODO
  1240  	case "darwin/arm64":
  1241  		blacklist["method-call.c"] = struct{}{} //TODO
  1242  	case "windows/amd64":
  1243  		blacklist["except.c"] = struct{}{}     //TODO
  1244  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1245  	case "windows/arm64":
  1246  		blacklist["except.c"] = struct{}{}     //TODO
  1247  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1248  	case "windows/386":
  1249  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1250  	case "linux/s390x":
  1251  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1252  	}
  1253  	binary := map[string]bool{
  1254  		"mandelbrot.c": true,
  1255  	}
  1256  	var rq, res, ok int
  1257  	limit := runtime.GOMAXPROCS(0)
  1258  	limiter := make(chan struct{}, limit)
  1259  	success := make([]string, 0, 0)
  1260  	results := make(chan *runResult, limit)
  1261  	failed := map[string]struct{}{}
  1262  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1263  		if !strings.HasSuffix(pth, ".c") {
  1264  			return nil
  1265  		}
  1266  
  1267  		switch {
  1268  		case re != nil:
  1269  			if !re.MatchString(pth) {
  1270  				return nil
  1271  			}
  1272  		default:
  1273  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1274  				return nil
  1275  			}
  1276  		}
  1277  
  1278  	more:
  1279  		select {
  1280  		case r := <-results:
  1281  			res++
  1282  			<-limiter
  1283  			switch r.err.(type) {
  1284  			case nil:
  1285  				ok++
  1286  				success = append(success, filepath.Base(r.name))
  1287  				delete(failed, r.name)
  1288  			case skipErr:
  1289  				delete(failed, r.name)
  1290  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1291  			default:
  1292  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1293  			}
  1294  			goto more
  1295  		case limiter <- struct{}{}:
  1296  			rq++
  1297  			if *oTrace {
  1298  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1299  			}
  1300  			failed[pth] = struct{}{}
  1301  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1302  		}
  1303  		return nil
  1304  	})
  1305  	if err != nil {
  1306  		t.Fatal(err)
  1307  	}
  1308  	for res != rq {
  1309  		r := <-results
  1310  		res++
  1311  		<-limiter
  1312  		switch r.err.(type) {
  1313  		case nil:
  1314  			ok++
  1315  			success = append(success, filepath.Base(r.name))
  1316  			delete(failed, r.name)
  1317  		case skipErr:
  1318  			delete(failed, r.name)
  1319  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1320  		default:
  1321  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1322  		}
  1323  	}
  1324  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1325  	sort.Strings(success)
  1326  	for _, fpath := range success {
  1327  		g.w.Write([]byte(fpath))
  1328  		g.w.Write([]byte{'\n'})
  1329  	}
  1330  	if len(failed) == 0 {
  1331  		return
  1332  	}
  1333  
  1334  	var a []string
  1335  	for k := range failed {
  1336  		a = append(a, k)
  1337  	}
  1338  	sort.Strings(a)
  1339  	for _, v := range a {
  1340  		t.Logf("FAIL %s", v)
  1341  	}
  1342  }
  1343  
  1344  func TestMirAndrewChambers(t *testing.T) {
  1345  	const root = "/github.com/vnmakarov/mir/c-tests/andrewchambers_c"
  1346  	g := newGolden(t, fmt.Sprintf("testdata/mir_andrew_chambers_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1347  
  1348  	defer g.close()
  1349  
  1350  	mustEmptyDir(t, tempDir, keep)
  1351  	wd, err := os.Getwd()
  1352  	if err != nil {
  1353  		t.Fatal(err)
  1354  	}
  1355  
  1356  	if err := os.Chdir(tempDir); err != nil {
  1357  		t.Fatal(err)
  1358  	}
  1359  
  1360  	defer func() {
  1361  		if err := os.Chdir(wd); err != nil {
  1362  			t.Fatal(err)
  1363  		}
  1364  	}()
  1365  
  1366  	blacklist := map[string]struct{}{
  1367  		"0011-switch1.c": {}, //TODO
  1368  		"0025-duff.c":    {}, //TODO
  1369  		"0028-inits06.c": {}, //TODO
  1370  		"0028-inits10.c": {}, //TODO
  1371  		"0028-inits11.c": {}, //TODO
  1372  		"0028-inits12.c": {}, //TODO
  1373  		"0028-inits13.c": {}, //TODO
  1374  		"0028-inits15.c": {}, //TODO
  1375  	}
  1376  	binary := map[string]bool{}
  1377  	var rq, res, ok int
  1378  	limit := runtime.GOMAXPROCS(0)
  1379  	limiter := make(chan struct{}, limit)
  1380  	success := make([]string, 0, 0)
  1381  	results := make(chan *runResult, limit)
  1382  	failed := map[string]struct{}{}
  1383  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1384  		if !strings.HasSuffix(pth, ".c") {
  1385  			return nil
  1386  		}
  1387  
  1388  		switch {
  1389  		case re != nil:
  1390  			if !re.MatchString(pth) {
  1391  				return nil
  1392  			}
  1393  		default:
  1394  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1395  				return nil
  1396  			}
  1397  		}
  1398  
  1399  	more:
  1400  		select {
  1401  		case r := <-results:
  1402  			res++
  1403  			<-limiter
  1404  			switch r.err.(type) {
  1405  			case nil:
  1406  				ok++
  1407  				success = append(success, filepath.Base(r.name))
  1408  				delete(failed, r.name)
  1409  			case skipErr:
  1410  				delete(failed, r.name)
  1411  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1412  			default:
  1413  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1414  			}
  1415  			goto more
  1416  		case limiter <- struct{}{}:
  1417  			rq++
  1418  			if *oTrace {
  1419  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1420  			}
  1421  			failed[pth] = struct{}{}
  1422  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1423  		}
  1424  		return nil
  1425  	})
  1426  	if err != nil {
  1427  		t.Fatal(err)
  1428  	}
  1429  	for res != rq {
  1430  		r := <-results
  1431  		res++
  1432  		<-limiter
  1433  		switch r.err.(type) {
  1434  		case nil:
  1435  			ok++
  1436  			success = append(success, filepath.Base(r.name))
  1437  			delete(failed, r.name)
  1438  		case skipErr:
  1439  			delete(failed, r.name)
  1440  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1441  		default:
  1442  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1443  		}
  1444  	}
  1445  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1446  	sort.Strings(success)
  1447  	for _, fpath := range success {
  1448  		g.w.Write([]byte(fpath))
  1449  		g.w.Write([]byte{'\n'})
  1450  	}
  1451  	if len(failed) == 0 {
  1452  		return
  1453  	}
  1454  
  1455  	var a []string
  1456  	for k := range failed {
  1457  		a = append(a, k)
  1458  	}
  1459  	sort.Strings(a)
  1460  	for _, v := range a {
  1461  		t.Logf("FAIL %s", v)
  1462  	}
  1463  }
  1464  
  1465  func TestMirLacc(t *testing.T) {
  1466  	const root = "/github.com/vnmakarov/mir/c-tests/lacc"
  1467  	g := newGolden(t, fmt.Sprintf("testdata/mir_lacc_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1468  
  1469  	defer g.close()
  1470  
  1471  	mustEmptyDir(t, tempDir, keep)
  1472  	wd, err := os.Getwd()
  1473  	if err != nil {
  1474  		t.Fatal(err)
  1475  	}
  1476  
  1477  	if err := os.Chdir(tempDir); err != nil {
  1478  		t.Fatal(err)
  1479  	}
  1480  
  1481  	defer func() {
  1482  		if err := os.Chdir(wd); err != nil {
  1483  			t.Fatal(err)
  1484  		}
  1485  	}()
  1486  
  1487  	needFiles(t, root, []string{
  1488  		"hello.c",
  1489  		"header.h",
  1490  	})
  1491  	blacklist := map[string]struct{}{
  1492  		"anonymous-struct.c":       {}, //TODO
  1493  		"array-registers.c":        {}, //TODO
  1494  		"bitfield-basic.c":         {}, //TODO
  1495  		"bitfield-extend.c":        {}, //TODO
  1496  		"bitfield-pack-next.c":     {}, //TODO
  1497  		"bitfield-trailing-zero.c": {}, //TODO
  1498  		"bitfield-types-init.c":    {}, //TODO
  1499  		"bitfield.c":               {}, //TODO
  1500  		"conditional-void.c":       {}, //TODO
  1501  		"declarator-complex.c":     {}, //TODO
  1502  		"duffs-device.c":           {}, //TODO
  1503  		"function-incomplete.c":    {}, //TODO
  1504  		"function-pointer-call.c":  {}, //TODO
  1505  		"function-pointer.c":       {}, //TODO
  1506  		"function.c":               {}, //TODO
  1507  		"hello.c":                  {}, //TODO
  1508  		"immediate-expr.c":         {}, //TODO
  1509  		"include.c":                {}, //TODO
  1510  		"ldouble-load-direct.c":    {}, //TODO
  1511  		"long-double-arithmetic.c": {}, //TODO
  1512  		"long-double-compare.c":    {}, //TODO
  1513  		"long-double-function.c":   {}, //TODO
  1514  		"long-double-load.c":       {}, //TODO
  1515  		"long-double-struct.c":     {}, //TODO
  1516  		"long-double-union.c":      {}, //TODO
  1517  		"macro-paste.c":            {}, //TODO
  1518  		"macro.c":                  {}, //TODO
  1519  		"pointer.c":                {}, //TODO
  1520  		"string-addr.c":            {}, //TODO
  1521  		"string-concat.c":          {}, //TODO
  1522  		"string-escape.c":          {}, //TODO
  1523  		"string-index.c":           {}, //TODO
  1524  		"string-length.c":          {}, //TODO
  1525  		"stringify.c":              {}, //TODO
  1526  		"strings.c":                {}, //TODO
  1527  		"token.c":                  {}, //TODO
  1528  		"typedef.c":                {}, //TODO
  1529  		"union-bitfield.c":         {}, //TODO
  1530  		"vararg-complex-1.c":       {}, //TODO
  1531  		"vararg-complex-2.c":       {}, //TODO
  1532  		"vararg.c":                 {}, //TODO
  1533  		"whitespace.c":             {}, //TODO
  1534  	}
  1535  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  1536  	case "linux/386":
  1537  		blacklist["convert-unsigned-float.c"] = struct{}{} //TODO  Go1.18 https://github.com/golang/go/issues/48807 ?
  1538  	case "freebsd/386":
  1539  		blacklist["convert-unsigned-float.c"] = struct{}{} //TODO  Go1.18 https://github.com/golang/go/issues/48807 ?
  1540  	case "windows/amd64":
  1541  		blacklist["convert-unsigned-float.c"] = struct{}{} //TODO  Go1.18 https://github.com/golang/go/issues/48807 ?
  1542  		blacklist["immediate-pointer.c"] = struct{}{}      //TODO
  1543  		blacklist["unsigned-sign-extend.c"] = struct{}{}   //TODO
  1544  	case "windows/arm64":
  1545  		blacklist["convert-unsigned-float.c"] = struct{}{} //TODO  Go1.18 https://github.com/golang/go/issues/48807 ?
  1546  		blacklist["immediate-pointer.c"] = struct{}{}      //TODO
  1547  		blacklist["unsigned-sign-extend.c"] = struct{}{}   //TODO
  1548  	case "windows/386":
  1549  		blacklist["convert-unsigned-float.c"] = struct{}{} //TODO  Go1.18 https://github.com/golang/go/issues/48807 ?
  1550  		blacklist["unsigned-sign-extend.c"] = struct{}{}   //TODO
  1551  	}
  1552  	binary := map[string]bool{}
  1553  	var rq, res, ok int
  1554  	limit := runtime.GOMAXPROCS(0)
  1555  	limiter := make(chan struct{}, limit)
  1556  	success := make([]string, 0, 0)
  1557  	results := make(chan *runResult, limit)
  1558  	failed := map[string]struct{}{}
  1559  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1560  		if !strings.HasSuffix(pth, ".c") {
  1561  			return nil
  1562  		}
  1563  
  1564  		switch {
  1565  		case re != nil:
  1566  			if !re.MatchString(pth) {
  1567  				return nil
  1568  			}
  1569  		default:
  1570  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1571  				return nil
  1572  			}
  1573  		}
  1574  
  1575  	more:
  1576  		select {
  1577  		case r := <-results:
  1578  			res++
  1579  			<-limiter
  1580  			switch r.err.(type) {
  1581  			case nil:
  1582  				ok++
  1583  				success = append(success, filepath.Base(r.name))
  1584  				delete(failed, r.name)
  1585  			case skipErr:
  1586  				delete(failed, r.name)
  1587  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1588  			default:
  1589  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1590  			}
  1591  			goto more
  1592  		case limiter <- struct{}{}:
  1593  			rq++
  1594  			if *oTrace {
  1595  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1596  			}
  1597  			failed[pth] = struct{}{}
  1598  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1599  		}
  1600  		return nil
  1601  	})
  1602  	if err != nil {
  1603  		t.Fatal(err)
  1604  	}
  1605  	for res != rq {
  1606  		r := <-results
  1607  		res++
  1608  		<-limiter
  1609  		switch r.err.(type) {
  1610  		case nil:
  1611  			ok++
  1612  			success = append(success, filepath.Base(r.name))
  1613  			delete(failed, r.name)
  1614  		case skipErr:
  1615  			delete(failed, r.name)
  1616  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1617  		default:
  1618  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1619  		}
  1620  	}
  1621  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1622  	sort.Strings(success)
  1623  	for _, fpath := range success {
  1624  		g.w.Write([]byte(fpath))
  1625  		g.w.Write([]byte{'\n'})
  1626  	}
  1627  	if len(failed) == 0 {
  1628  		return
  1629  	}
  1630  
  1631  	var a []string
  1632  	for k := range failed {
  1633  		a = append(a, k)
  1634  	}
  1635  	sort.Strings(a)
  1636  	for _, v := range a {
  1637  		t.Logf("FAIL %s", v)
  1638  	}
  1639  }
  1640  
  1641  func TestMirNew(t *testing.T) {
  1642  	const root = "/github.com/vnmakarov/mir/c-tests/new"
  1643  	g := newGolden(t, fmt.Sprintf("testdata/mir_new_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1644  
  1645  	defer g.close()
  1646  
  1647  	mustEmptyDir(t, tempDir, keep)
  1648  	wd, err := os.Getwd()
  1649  	if err != nil {
  1650  		t.Fatal(err)
  1651  	}
  1652  
  1653  	if err := os.Chdir(tempDir); err != nil {
  1654  		t.Fatal(err)
  1655  	}
  1656  
  1657  	defer func() {
  1658  		if err := os.Chdir(wd); err != nil {
  1659  			t.Fatal(err)
  1660  		}
  1661  	}()
  1662  
  1663  	blacklist := map[string]struct{}{
  1664  		// 1: /github.com/vnmakarov/mir/c-tests/new/endif.c
  1665  		//     all_test.go:1045: /github.com/vnmakarov/mir/c-tests/new/endif.c: /usr/bin/gcc: system C compiler: exit status 1
  1666  		//         endif.c:1:2: error: #endif without #if
  1667  		//          #endif
  1668  		//           ^~~~~
  1669  		"endif.c": {}, // No intent to support.
  1670  
  1671  		// 1: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c
  1672  		//     all_test.go:1051: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c: /usr/bin/gcc: system C compiler: exit status 1
  1673  		//         fermian-2.c:1:3: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
  1674  		//          a {
  1675  		//            ^
  1676  		"fermian-2.c": {}, // No intent to support.
  1677  		"fermian.c":   {}, // No main.
  1678  
  1679  		"issue142.c": {}, //TODO
  1680  		"issue18.c":  {}, //TODO
  1681  		"issue23.c":  {}, //TODO
  1682  		"setjmp.c":   {}, //TODO
  1683  		"setjmp2.c":  {}, //TODO
  1684  	}
  1685  	binary := map[string]bool{}
  1686  	var rq, res, ok int
  1687  	limit := runtime.GOMAXPROCS(0)
  1688  	limiter := make(chan struct{}, limit)
  1689  	success := make([]string, 0, 0)
  1690  	results := make(chan *runResult, limit)
  1691  	failed := map[string]struct{}{}
  1692  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1693  		if !strings.HasSuffix(pth, ".c") {
  1694  			return nil
  1695  		}
  1696  
  1697  		switch {
  1698  		case re != nil:
  1699  			if !re.MatchString(pth) {
  1700  				return nil
  1701  			}
  1702  		default:
  1703  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1704  				return nil
  1705  			}
  1706  		}
  1707  
  1708  	more:
  1709  		select {
  1710  		case r := <-results:
  1711  			res++
  1712  			<-limiter
  1713  			switch r.err.(type) {
  1714  			case nil:
  1715  				ok++
  1716  				success = append(success, filepath.Base(r.name))
  1717  				delete(failed, r.name)
  1718  			case skipErr:
  1719  				delete(failed, r.name)
  1720  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1721  			default:
  1722  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1723  			}
  1724  			goto more
  1725  		case limiter <- struct{}{}:
  1726  			rq++
  1727  			if *oTrace {
  1728  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1729  			}
  1730  			failed[pth] = struct{}{}
  1731  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1732  		}
  1733  		return nil
  1734  	})
  1735  	if err != nil {
  1736  		t.Fatal(err)
  1737  	}
  1738  	for res != rq {
  1739  		r := <-results
  1740  		res++
  1741  		<-limiter
  1742  		switch r.err.(type) {
  1743  		case nil:
  1744  			ok++
  1745  			success = append(success, filepath.Base(r.name))
  1746  			delete(failed, r.name)
  1747  		case skipErr:
  1748  			delete(failed, r.name)
  1749  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1750  		default:
  1751  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1752  		}
  1753  	}
  1754  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1755  	sort.Strings(success)
  1756  	for _, fpath := range success {
  1757  		g.w.Write([]byte(fpath))
  1758  		g.w.Write([]byte{'\n'})
  1759  	}
  1760  	if len(failed) == 0 {
  1761  		return
  1762  	}
  1763  
  1764  	var a []string
  1765  	for k := range failed {
  1766  		a = append(a, k)
  1767  	}
  1768  	sort.Strings(a)
  1769  	for _, v := range a {
  1770  		t.Logf("FAIL %s", v)
  1771  	}
  1772  }
  1773  
  1774  func TestCompCert(t *testing.T) {
  1775  	const root = "/github.com/AbsInt/CompCert/test/c/"
  1776  	g := newGolden(t, fmt.Sprintf("testdata/compcert_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1777  
  1778  	defer g.close()
  1779  
  1780  	mustEmptyDir(t, tempDir, keep)
  1781  	wd, err := os.Getwd()
  1782  	if err != nil {
  1783  		t.Fatal(err)
  1784  	}
  1785  
  1786  	if err := os.Chdir(tempDir); err != nil {
  1787  		t.Fatal(err)
  1788  	}
  1789  
  1790  	defer func() {
  1791  		if err := os.Chdir(wd); err != nil {
  1792  			t.Fatal(err)
  1793  		}
  1794  	}()
  1795  
  1796  	needFiles(t, root, []string{
  1797  		"Results/knucleotide-input.txt",
  1798  		"endian.h",
  1799  	})
  1800  	blacklist := map[string]struct{}{}
  1801  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  1802  	case "windows/386":
  1803  		blacklist["bisect.c"] = struct{}{}     //TODO
  1804  		blacklist["fftw.c"] = struct{}{}       //TODO
  1805  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1806  		blacklist["perlin.c"] = struct{}{}     //TODO
  1807  	case "windows/amd64":
  1808  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1809  	case "windows/arm64":
  1810  		blacklist["mandelbrot.c"] = struct{}{} //TODO
  1811  	}
  1812  	binary := map[string]bool{
  1813  		"mandelbrot.c": true,
  1814  	}
  1815  	var rq, res, ok int
  1816  	limit := runtime.GOMAXPROCS(0)
  1817  	limiter := make(chan struct{}, limit)
  1818  	success := make([]string, 0, 0)
  1819  	results := make(chan *runResult, limit)
  1820  	failed := map[string]struct{}{}
  1821  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1822  		if !strings.HasSuffix(pth, ".c") {
  1823  			return nil
  1824  		}
  1825  
  1826  		switch {
  1827  		case re != nil:
  1828  			if !re.MatchString(pth) {
  1829  				return nil
  1830  			}
  1831  		default:
  1832  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1833  				return nil
  1834  			}
  1835  		}
  1836  
  1837  	more:
  1838  		select {
  1839  		case r := <-results:
  1840  			res++
  1841  			<-limiter
  1842  			switch r.err.(type) {
  1843  			case nil:
  1844  				ok++
  1845  				success = append(success, filepath.Base(r.name))
  1846  				delete(failed, r.name)
  1847  			case skipErr:
  1848  				delete(failed, r.name)
  1849  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1850  			default:
  1851  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1852  			}
  1853  			goto more
  1854  		case limiter <- struct{}{}:
  1855  			rq++
  1856  			if *oTrace {
  1857  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1858  			}
  1859  			failed[pth] = struct{}{}
  1860  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1861  		}
  1862  		return nil
  1863  	})
  1864  	if err != nil {
  1865  		t.Fatal(err)
  1866  	}
  1867  	for res != rq {
  1868  		r := <-results
  1869  		res++
  1870  		<-limiter
  1871  		switch r.err.(type) {
  1872  		case nil:
  1873  			ok++
  1874  			success = append(success, filepath.Base(r.name))
  1875  			delete(failed, r.name)
  1876  		case skipErr:
  1877  			delete(failed, r.name)
  1878  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1879  		default:
  1880  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1881  		}
  1882  	}
  1883  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1884  	sort.Strings(success)
  1885  	for _, fpath := range success {
  1886  		g.w.Write([]byte(fpath))
  1887  		g.w.Write([]byte{'\n'})
  1888  	}
  1889  	if len(failed) == 0 {
  1890  		return
  1891  	}
  1892  
  1893  	var a []string
  1894  	for k := range failed {
  1895  		a = append(a, k)
  1896  	}
  1897  	sort.Strings(a)
  1898  	for _, v := range a {
  1899  		t.Logf("FAIL %s", v)
  1900  	}
  1901  }
  1902  
  1903  func TestGCCExecute(t *testing.T) {
  1904  	const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute"
  1905  	g := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1906  
  1907  	defer g.close()
  1908  
  1909  	mustEmptyDir(t, tempDir, keep)
  1910  	wd, err := os.Getwd()
  1911  	if err != nil {
  1912  		t.Fatal(err)
  1913  	}
  1914  
  1915  	if err := os.Chdir(tempDir); err != nil {
  1916  		t.Fatal(err)
  1917  	}
  1918  
  1919  	defer func() {
  1920  		if err := os.Chdir(wd); err != nil {
  1921  			t.Fatal(err)
  1922  		}
  1923  	}()
  1924  
  1925  	// Prepare testdata
  1926  	needFiles(t, root, []string{
  1927  		"20040709-2.c",
  1928  	})
  1929  	blacklist := map[string]struct{}{
  1930  		// assembler
  1931  		"20001009-2.c": {},
  1932  
  1933  		// Nested function
  1934  		"20000822-1.c": {},
  1935  		"20010209-1.c": {},
  1936  		"20010605-1.c": {},
  1937  
  1938  		// Alignment > 8
  1939  		"20010904-1.c": {},
  1940  		"20010904-2.c": {},
  1941  
  1942  		// Variable sized type
  1943  		"20040423-1.c": {},
  1944  		"20040411-1.c": {},
  1945  
  1946  		// Relies on SIGFPE
  1947  		"20101011-1.c": {},
  1948  
  1949  		// Relies on gcc instrumentation
  1950  		"eeprof-1.c": {},
  1951  
  1952  		//TODO back-end: undefined: __builtin_return_address
  1953  		"20010122-1.c": {},
  1954  
  1955  		//TODO crash in cc
  1956  		"20010605-2.c": {},
  1957  
  1958  		//TODO flexible array members not supported
  1959  		"20010924-1.c": {},
  1960  
  1961  		//TODO TODO in go.go
  1962  		"20000113-1.c": {},
  1963  
  1964  		//TODO relies on link order, libc first
  1965  		"20021127-1.c": {},
  1966  
  1967  		//TODO #pragma push/pop macro
  1968  		"pushpop_macro.c": {},
  1969  
  1970  		//TODO not yet classified
  1971  		"20000801-3.c":                 {}, //TODO
  1972  		"20020107-1.c":                 {}, //TODO
  1973  		"20020206-2.c":                 {}, //TODO
  1974  		"20020227-1.c":                 {}, //TODO
  1975  		"20020314-1.c":                 {}, //TODO
  1976  		"20020320-1.c":                 {}, //TODO
  1977  		"20020411-1.c":                 {}, //TODO
  1978  		"20020412-1.c":                 {}, //TODO
  1979  		"20021113-1.c":                 {}, //TODO
  1980  		"20021120-1.c":                 {}, //TODO
  1981  		"20030109-1.c":                 {}, //TODO
  1982  		"20030128-1.c":                 {}, //TODO
  1983  		"20030222-1.c":                 {}, //TODO
  1984  		"20030501-1.c":                 {}, //TODO
  1985  		"20030910-1.c":                 {}, //TODO
  1986  		"20031003-1.c":                 {}, //TODO
  1987  		"20040223-1.c":                 {}, //TODO
  1988  		"20040302-1.c":                 {}, //TODO
  1989  		"20040308-1.c":                 {}, //TODO
  1990  		"20040520-1.c":                 {}, //TODO
  1991  		"20040629-1.c":                 {}, //TODO
  1992  		"20040705-1.c":                 {}, //TODO
  1993  		"20040705-2.c":                 {}, //TODO
  1994  		"20040707-1.c":                 {}, //TODO
  1995  		"20040709-1.c":                 {}, //TODO
  1996  		"20040709-2.c":                 {}, //TODO
  1997  		"20040709-3.c":                 {}, //TODO
  1998  		"20041011-1.c":                 {}, //TODO
  1999  		"20041124-1.c":                 {}, //TODO
  2000  		"20041201-1.c":                 {}, //TODO
  2001  		"20041214-1.c":                 {}, //TODO
  2002  		"20041218-2.c":                 {}, //TODO
  2003  		"20050121-1.c":                 {}, //TODO
  2004  		"20050316-1.c":                 {}, //TODO
  2005  		"20050316-2.c":                 {}, //TODO
  2006  		"20050316-3.c":                 {}, //TODO
  2007  		"20050604-1.c":                 {}, //TODO
  2008  		"20050607-1.c":                 {}, //TODO
  2009  		"20050613-1.c":                 {}, //TODO
  2010  		"20050929-1.c":                 {}, //TODO
  2011  		"20051012-1.c":                 {}, //TODO
  2012  		"20060420-1.c":                 {}, //TODO
  2013  		"20061220-1.c":                 {}, //TODO
  2014  		"20070614-1.c":                 {}, //TODO
  2015  		"20070824-1.c":                 {}, //TODO
  2016  		"20070919-1.c":                 {}, //TODO
  2017  		"20071210-1.c":                 {}, //TODO
  2018  		"20071211-1.c":                 {}, //TODO
  2019  		"20071220-1.c":                 {}, //TODO
  2020  		"20071220-2.c":                 {}, //TODO
  2021  		"20080502-1.c":                 {}, //TODO
  2022  		"20090219-1.c":                 {}, //TODO
  2023  		"20100430-1.c":                 {}, //TODO
  2024  		"20121108-1.c":                 {}, //TODO
  2025  		"20180921-1.c":                 {}, //TODO
  2026  		"920302-1.c":                   {}, //TODO
  2027  		"920415-1.c":                   {}, //TODO
  2028  		"920428-2.c":                   {}, //TODO
  2029  		"920501-1.c":                   {}, //TODO
  2030  		"920501-3.c":                   {}, //TODO
  2031  		"920501-4.c":                   {}, //TODO
  2032  		"920501-5.c":                   {}, //TODO
  2033  		"920501-7.c":                   {}, //TODO
  2034  		"920612-2.c":                   {}, //TODO
  2035  		"920625-1.c":                   {}, //TODO
  2036  		"920721-4.c":                   {}, //TODO
  2037  		"920908-1.c":                   {}, //TODO
  2038  		"921017-1.c":                   {}, //TODO
  2039  		"921202-1.c":                   {}, //TODO
  2040  		"921208-2.c":                   {}, //TODO
  2041  		"921215-1.c":                   {}, //TODO
  2042  		"930406-1.c":                   {}, //TODO
  2043  		"931002-1.c":                   {}, //TODO
  2044  		"931004-10.c":                  {}, //TODO
  2045  		"931004-12.c":                  {}, //TODO
  2046  		"931004-14.c":                  {}, //TODO
  2047  		"931004-2.c":                   {}, //TODO
  2048  		"931004-4.c":                   {}, //TODO
  2049  		"931004-6.c":                   {}, //TODO
  2050  		"931004-8.c":                   {}, //TODO
  2051  		"941014-1.c":                   {}, //TODO
  2052  		"941202-1.c":                   {}, //TODO
  2053  		"960312-1.c":                   {}, //TODO
  2054  		"960416-1.c":                   {}, //TODO
  2055  		"960512-1.c":                   {}, //TODO
  2056  		"970217-1.c":                   {}, //TODO
  2057  		"980526-1.c":                   {}, //TODO
  2058  		"990130-1.c":                   {}, //TODO
  2059  		"990208-1.c":                   {}, //TODO
  2060  		"990413-2.c":                   {}, //TODO
  2061  		"990524-1.c":                   {}, //TODO
  2062  		"991014-1.c":                   {}, //TODO
  2063  		"991112-1.c":                   {}, //TODO
  2064  		"991227-1.c":                   {}, //TODO
  2065  		"alias-2.c":                    {}, //TODO
  2066  		"alias-3.c":                    {}, //TODO
  2067  		"alias-4.c":                    {}, //TODO
  2068  		"align-3.c":                    {}, //TODO
  2069  		"align-nest.c":                 {}, //TODO
  2070  		"alloca-1.c":                   {}, //TODO
  2071  		"anon-1.c":                     {}, //TODO
  2072  		"bitfld-3.c":                   {}, //TODO
  2073  		"built-in-setjmp.c":            {}, //TODO
  2074  		"builtin-bitops-1.c":           {}, //TODO
  2075  		"builtin-constant.c":           {}, //TODO
  2076  		"builtin-prefetch-3.c":         {}, //TODO
  2077  		"builtin-types-compatible-p.c": {}, //TODO
  2078  		"call-trap-1.c":                {}, //TODO
  2079  		"comp-goto-1.c":                {}, //TODO
  2080  		"comp-goto-2.c":                {}, //TODO
  2081  		"complex-1.c":                  {}, //TODO
  2082  		"complex-2.c":                  {}, //TODO
  2083  		"complex-4.c":                  {}, //TODO
  2084  		"complex-5.c":                  {}, //TODO
  2085  		"complex-6.c":                  {}, //TODO
  2086  		"complex-7.c":                  {}, //TODO
  2087  		"ffs-1.c":                      {}, //TODO
  2088  		"ffs-2.c":                      {}, //TODO
  2089  		"fprintf-2.c":                  {}, //TODO
  2090  		"frame-address.c":              {}, //TODO
  2091  		"medce-1.c":                    {}, //TODO
  2092  		"nest-align-1.c":               {}, //TODO
  2093  		"nest-stdar-1.c":               {}, //TODO
  2094  		"nestfunc-1.c":                 {}, //TODO
  2095  		"nestfunc-2.c":                 {}, //TODO
  2096  		"nestfunc-3.c":                 {}, //TODO
  2097  		"nestfunc-5.c":                 {}, //TODO
  2098  		"nestfunc-6.c":                 {}, //TODO
  2099  		"nestfunc-7.c":                 {}, //TODO
  2100  		"pr17377.c":                    {}, //TODO
  2101  		"pr22061-1.c":                  {}, //TODO
  2102  		"pr22061-3.c":                  {}, //TODO
  2103  		"pr22061-4.c":                  {}, //TODO
  2104  		"pr23135.c":                    {}, //TODO
  2105  		"pr23324.c":                    {}, //TODO
  2106  		"pr23467.c":                    {}, //TODO
  2107  		"pr24135.c":                    {}, //TODO
  2108  		"pr28289.c":                    {}, //TODO
  2109  		"pr28865.c":                    {}, //TODO
  2110  		"pr33382.c":                    {}, //TODO
  2111  		"pr34154.c":                    {}, //TODO
  2112  		"pr35456.c":                    {}, //TODO
  2113  		"pr36321.c":                    {}, //TODO
  2114  		"pr37780.c":                    {}, //TODO
  2115  		"pr38151.c":                    {}, //TODO
  2116  		"pr38533.c":                    {}, //TODO
  2117  		"pr38969.c":                    {}, //TODO
  2118  		"pr39228.c":                    {}, //TODO
  2119  		"pr40022.c":                    {}, //TODO
  2120  		"pr40657.c":                    {}, //TODO
  2121  		"pr41239.c":                    {}, //TODO
  2122  		"pr41935.c":                    {}, //TODO
  2123  		"pr42248.c":                    {}, //TODO
  2124  		"pr43385.c":                    {}, //TODO
  2125  		"pr43560.c":                    {}, //TODO
  2126  		"pr44575.c":                    {}, //TODO
  2127  		"pr45695.c":                    {}, //TODO
  2128  		"pr46309.c":                    {}, //TODO
  2129  		"pr47237.c":                    {}, //TODO
  2130  		"pr49279.c":                    {}, //TODO
  2131  		"pr49390.c":                    {}, //TODO
  2132  		"pr49644.c":                    {}, //TODO
  2133  		"pr51447.c":                    {}, //TODO
  2134  		"pr51877.c":                    {}, //TODO
  2135  		"pr51933.c":                    {}, //TODO
  2136  		"pr52286.c":                    {}, //TODO
  2137  		"pr53160.c":                    {}, //TODO
  2138  		"pr53645-2.c":                  {}, //TODO
  2139  		"pr53645.c":                    {}, //TODO
  2140  		"pr56205.c":                    {}, //TODO
  2141  		"pr56837.c":                    {}, //TODO
  2142  		"pr56866.c":                    {}, //TODO
  2143  		"pr56982.c":                    {}, //TODO
  2144  		"pr57344-1.c":                  {}, //TODO
  2145  		"pr57344-2.c":                  {}, //TODO
  2146  		"pr57344-3.c":                  {}, //TODO
  2147  		"pr57344-4.c":                  {}, //TODO
  2148  		"pr60003.c":                    {}, //TODO
  2149  		"pr60960.c":                    {}, //TODO
  2150  		"pr61725.c":                    {}, //TODO
  2151  		"pr63641.c":                    {}, //TODO
  2152  		"pr64006.c":                    {}, //TODO
  2153  		"pr64242.c":                    {}, //TODO
  2154  		"pr65053-2.c":                  {}, //TODO
  2155  		"pr65427.c":                    {}, //TODO
  2156  		"pr65648.c":                    {}, //TODO
  2157  		"pr65956.c":                    {}, //TODO
  2158  		"pr66556.c":                    {}, //TODO
  2159  		"pr67037.c":                    {}, //TODO
  2160  		"pr68249.c":                    {}, //TODO
  2161  		"pr68328.c":                    {}, //TODO
  2162  		"pr68381.c":                    {}, //TODO
  2163  		"pr69320-2.c":                  {}, //TODO
  2164  		"pr70460.c":                    {}, //TODO
  2165  		"pr70903.c":                    {}, //TODO
  2166  		"pr71494.c":                    {}, //TODO
  2167  		"pr71554.c":                    {}, //TODO
  2168  		"pr71626-1.c":                  {}, //TODO
  2169  		"pr71626-2.c":                  {}, //TODO
  2170  		"pr71631.c":                    {}, //TODO
  2171  		"pr77767.c":                    {}, //TODO
  2172  		"pr78438.c":                    {}, //TODO
  2173  		"pr78726.c":                    {}, //TODO
  2174  		"pr79354.c":                    {}, //TODO
  2175  		"pr79737-2.c":                  {}, //TODO
  2176  		"pr80421.c":                    {}, //TODO
  2177  		"pr80692.c":                    {}, //TODO
  2178  		"pr81588.c":                    {}, //TODO
  2179  		"pr82210.c":                    {}, //TODO
  2180  		"pr82954.c":                    {}, //TODO
  2181  		"pr84478.c":                    {}, //TODO
  2182  		"pr84521.c":                    {}, //TODO
  2183  		"pr84524.c":                    {}, //TODO
  2184  		"pr85156.c":                    {}, //TODO
  2185  		"pr85169.c":                    {}, //TODO
  2186  		"pr85331.c":                    {}, //TODO
  2187  		"pr85529-1.c":                  {}, //TODO
  2188  		"pr86528.c":                    {}, //TODO
  2189  		"pr89195.c":                    {}, //TODO
  2190  		"pr89434.c":                    {}, //TODO
  2191  		"pr90311.c":                    {}, //TODO
  2192  		"pr91450-1.c":                  {}, //TODO
  2193  		"pr91450-2.c":                  {}, //TODO
  2194  		"pr91635.c":                    {}, //TODO
  2195  		"pr92618.c":                    {}, //TODO
  2196  		"pr92904.c":                    {}, //TODO
  2197  		"pr93213.c":                    {}, //TODO
  2198  		"pr93249.c":                    {}, //TODO
  2199  		"pr93434.c":                    {}, //TODO
  2200  		"pr93494.c":                    {}, //TODO
  2201  		"pr93744-1.c":                  {}, //TODO
  2202  		"pr93945.c":                    {}, //TODO
  2203  		"pr94130.c":                    {}, //TODO
  2204  		"pr94412.c":                    {}, //TODO
  2205  		"pr94524-1.c":                  {}, //TODO
  2206  		"pr94524-2.c":                  {}, //TODO
  2207  		"pr94591.c":                    {}, //TODO
  2208  		"pr97325.c":                    {}, //TODO
  2209  		"pr98366.c":                    {}, //TODO
  2210  		"pr98474.c":                    {}, //TODO
  2211  		"pr98681.c":                    {}, //TODO
  2212  		"printf-2.c":                   {}, //TODO
  2213  		"return-addr.c":                {}, //TODO
  2214  		"scal-to-vec1.c":               {}, //TODO
  2215  		"scal-to-vec2.c":               {}, //TODO
  2216  		"scal-to-vec3.c":               {}, //TODO
  2217  		"simd-1.c":                     {}, //TODO
  2218  		"simd-2.c":                     {}, //TODO
  2219  		"simd-4.c":                     {}, //TODO
  2220  		"simd-5.c":                     {}, //TODO
  2221  		"simd-6.c":                     {}, //TODO
  2222  		"stdarg-3.c":                   {}, //TODO
  2223  		"stkalign.c":                   {}, //TODO
  2224  		"strct-stdarg-1.c":             {}, //TODO
  2225  		"strct-varg-1.c":               {}, //TODO
  2226  		"string-opt-18.c":              {}, //TODO
  2227  		"string-opt-5.c":               {}, //TODO
  2228  		"user-printf.c":                {}, //TODO
  2229  		"va-arg-2.c":                   {}, //TODO
  2230  		"va-arg-22.c":                  {}, //TODO
  2231  		"va-arg-pack-1.c":              {}, //TODO
  2232  		"zero-struct-2.c":              {}, //TODO
  2233  	}
  2234  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  2235  	case "freebsd/386":
  2236  		// asm
  2237  		blacklist["960830-1.c"] = struct{}{}
  2238  	case "linux/386":
  2239  		// asm
  2240  		blacklist["960830-1.c"] = struct{}{}
  2241  	case "linux/arm64":
  2242  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO
  2243  	case "linux/s390x":
  2244  		blacklist["pr58574.c"] = struct{}{}        //TODO
  2245  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO
  2246  	case "windows/amd64":
  2247  		blacklist["941014-2.c"] = struct{}{} //TODO
  2248  		blacklist["pr36339.c"] = struct{}{}  //TODO
  2249  		blacklist["pr78622.c"] = struct{}{}  //TODO
  2250  	case "windows/arm64":
  2251  		blacklist["941014-2.c"] = struct{}{} //TODO
  2252  		blacklist["pr36339.c"] = struct{}{}  //TODO
  2253  		blacklist["pr61375.c"] = struct{}{}  //TODO
  2254  		blacklist["pr65170.c"] = struct{}{}  //TODO
  2255  		blacklist["pr78622.c"] = struct{}{}  //TODO
  2256  		blacklist["pr84169.c"] = struct{}{}  //TODO
  2257  	case "windows/386":
  2258  		blacklist["941014-2.c"] = struct{}{} //TODO
  2259  		blacklist["960830-1.c"] = struct{}{} //TODO
  2260  		blacklist["pr78622.c"] = struct{}{}  //TODO
  2261  	}
  2262  	binary := map[string]bool{}
  2263  	var rq, res, ok int
  2264  	limit := runtime.GOMAXPROCS(0)
  2265  	limiter := make(chan struct{}, limit)
  2266  	success := make([]string, 0, 0)
  2267  	results := make(chan *runResult, limit)
  2268  	failed := map[string]struct{}{}
  2269  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2270  		if strings.Contains(pth, "/ieee/") || !strings.HasSuffix(pth, ".c") {
  2271  			return nil
  2272  		}
  2273  
  2274  		switch {
  2275  		case re != nil:
  2276  			if !re.MatchString(pth) {
  2277  				return nil
  2278  			}
  2279  		default:
  2280  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2281  				return nil
  2282  			}
  2283  		}
  2284  
  2285  	more:
  2286  		select {
  2287  		case r := <-results:
  2288  			res++
  2289  			<-limiter
  2290  			switch r.err.(type) {
  2291  			case nil:
  2292  				ok++
  2293  				success = append(success, filepath.Base(r.name))
  2294  				delete(failed, r.name)
  2295  			case skipErr:
  2296  				delete(failed, r.name)
  2297  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2298  			default:
  2299  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2300  			}
  2301  			goto more
  2302  		case limiter <- struct{}{}:
  2303  			rq++
  2304  			if *oTrace {
  2305  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2306  			}
  2307  			base := filepath.Base(pth)
  2308  			failed[pth] = struct{}{}
  2309  			go run(pth, binary[base], false, false, results)
  2310  		}
  2311  		return nil
  2312  	})
  2313  	if err != nil {
  2314  		t.Fatal(err)
  2315  	}
  2316  	for res != rq {
  2317  		r := <-results
  2318  		res++
  2319  		<-limiter
  2320  		switch r.err.(type) {
  2321  		case nil:
  2322  			ok++
  2323  			success = append(success, filepath.Base(r.name))
  2324  			delete(failed, r.name)
  2325  		case skipErr:
  2326  			delete(failed, r.name)
  2327  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2328  		default:
  2329  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2330  		}
  2331  	}
  2332  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2333  	sort.Strings(success)
  2334  	for _, fpath := range success {
  2335  		g.w.Write([]byte(fpath))
  2336  		g.w.Write([]byte{'\n'})
  2337  	}
  2338  	if len(failed) == 0 {
  2339  		return
  2340  	}
  2341  
  2342  	var a []string
  2343  	for k := range failed {
  2344  		a = append(a, k)
  2345  	}
  2346  	sort.Strings(a)
  2347  	for _, v := range a {
  2348  		t.Logf("FAIL %s", v)
  2349  	}
  2350  }
  2351  
  2352  func TestGCCExecuteIEEE(t *testing.T) {
  2353  	const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute/ieee"
  2354  	g := newGolden(t, fmt.Sprintf("testdata/gcc_ieee_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  2355  
  2356  	defer g.close()
  2357  
  2358  	mustEmptyDir(t, tempDir, keep)
  2359  	wd, err := os.Getwd()
  2360  	if err != nil {
  2361  		t.Fatal(err)
  2362  	}
  2363  
  2364  	if err := os.Chdir(tempDir); err != nil {
  2365  		t.Fatal(err)
  2366  	}
  2367  
  2368  	defer func() {
  2369  		if err := os.Chdir(wd); err != nil {
  2370  			t.Fatal(err)
  2371  		}
  2372  	}()
  2373  
  2374  	blacklist := map[string]struct{}{
  2375  		"compare-fp-1.c": {}, //TODO
  2376  		"compare-fp-4.c": {}, //TODO
  2377  		"copysign1.c":    {}, //TODO
  2378  		"copysign2.c":    {}, //TODO
  2379  		"fp-cmp-4.c":     {}, //TODO
  2380  		"fp-cmp-4f.c":    {}, //TODO
  2381  		"fp-cmp-4l.c":    {}, //TODO
  2382  		"fp-cmp-5.c":     {}, //TODO
  2383  		"fp-cmp-8.c":     {}, //TODO
  2384  		"fp-cmp-8f.c":    {}, //TODO
  2385  		"fp-cmp-8l.c":    {}, //TODO
  2386  		"inf-1.c":        {}, //TODO
  2387  		"inf-3.c":        {}, //TODO
  2388  		"mzero4.c":       {}, //TODO
  2389  		"pr36332.c":      {}, //TODO
  2390  		"pr38016.c":      {}, //TODO
  2391  		"pr50310.c":      {}, //TODO
  2392  		"pr72824-2.c":    {}, //TODO
  2393  	}
  2394  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  2395  	case "linux/386":
  2396  		blacklist["rbug.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807
  2397  	case "freebsd/386":
  2398  		blacklist["rbug.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807
  2399  	case "linux/arm":
  2400  		blacklist["compare-fp-3.c"] = struct{}{} //TODO
  2401  		blacklist["rbug.c"] = struct{}{}         //TODO
  2402  	case "linux/s390x":
  2403  		blacklist["compare-fp-3.c"] = struct{}{} //TODO
  2404  	case "windows/amd64":
  2405  		blacklist["fp-cmp-1.c"] = struct{}{} //TODO
  2406  		blacklist["fp-cmp-2.c"] = struct{}{} //TODO
  2407  		blacklist["fp-cmp-3.c"] = struct{}{} //TODO
  2408  	case "windows/arm64":
  2409  		blacklist["fp-cmp-1.c"] = struct{}{} //TODO
  2410  		blacklist["fp-cmp-2.c"] = struct{}{} //TODO
  2411  		blacklist["fp-cmp-3.c"] = struct{}{} //TODO
  2412  		blacklist["fp-cmp-7.c"] = struct{}{} //TODO
  2413  	case "windows/386":
  2414  		blacklist["fp-cmp-1.c"] = struct{}{} //TODO
  2415  		blacklist["fp-cmp-2.c"] = struct{}{} //TODO
  2416  		blacklist["fp-cmp-3.c"] = struct{}{} //TODO
  2417  		blacklist["rbug.c"] = struct{}{}     //TODO
  2418  	case "netbsd/amd64":
  2419  		blacklist["compare-fp-3.c"] = struct{}{} //TODO
  2420  		blacklist["fp-cmp-7.c"] = struct{}{}     //TODO
  2421  	case "openbsd/amd64":
  2422  		blacklist["fp-cmp-7.c"] = struct{}{} //TODO
  2423  	case "freebsd/arm":
  2424  		blacklist["fp-cmp-7.c"] = struct{}{} //TODO
  2425  	}
  2426  	binary := map[string]bool{}
  2427  	var rq, res, ok int
  2428  	limit := runtime.GOMAXPROCS(0)
  2429  	limiter := make(chan struct{}, limit)
  2430  	success := make([]string, 0, 0)
  2431  	results := make(chan *runResult, limit)
  2432  	failed := map[string]struct{}{}
  2433  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2434  		if !strings.HasSuffix(pth, ".c") {
  2435  			return nil
  2436  		}
  2437  
  2438  		switch {
  2439  		case re != nil:
  2440  			if !re.MatchString(pth) {
  2441  				return nil
  2442  			}
  2443  		default:
  2444  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2445  				return nil
  2446  			}
  2447  		}
  2448  
  2449  	more:
  2450  		select {
  2451  		case r := <-results:
  2452  			res++
  2453  			<-limiter
  2454  			switch r.err.(type) {
  2455  			case nil:
  2456  				ok++
  2457  				success = append(success, filepath.Base(r.name))
  2458  				delete(failed, r.name)
  2459  			case skipErr:
  2460  				delete(failed, r.name)
  2461  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2462  			default:
  2463  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2464  			}
  2465  			goto more
  2466  		case limiter <- struct{}{}:
  2467  			rq++
  2468  			if *oTrace {
  2469  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2470  			}
  2471  			failed[pth] = struct{}{}
  2472  			go run(pth, binary[filepath.Base(pth)], true, false, results)
  2473  		}
  2474  		return nil
  2475  	})
  2476  	if err != nil {
  2477  		t.Fatal(err)
  2478  	}
  2479  	for res != rq {
  2480  		r := <-results
  2481  		res++
  2482  		<-limiter
  2483  		switch r.err.(type) {
  2484  		case nil:
  2485  			ok++
  2486  			success = append(success, filepath.Base(r.name))
  2487  			delete(failed, r.name)
  2488  		case skipErr:
  2489  			delete(failed, r.name)
  2490  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2491  		default:
  2492  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2493  		}
  2494  	}
  2495  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2496  	sort.Strings(success)
  2497  	for _, fpath := range success {
  2498  		g.w.Write([]byte(fpath))
  2499  		g.w.Write([]byte{'\n'})
  2500  	}
  2501  	if len(failed) == 0 {
  2502  		return
  2503  	}
  2504  
  2505  	var a []string
  2506  	for k := range failed {
  2507  		a = append(a, k)
  2508  	}
  2509  	sort.Strings(a)
  2510  	for _, v := range a {
  2511  		t.Logf("FAIL %s", v)
  2512  	}
  2513  }
  2514  
  2515  func TestCxgo(t *testing.T) {
  2516  	const root = "/github.com/cxgo"
  2517  	g := newGolden(t, fmt.Sprintf("testdata/cxgo_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  2518  
  2519  	defer g.close()
  2520  
  2521  	mustEmptyDir(t, tempDir, keep)
  2522  	wd, err := os.Getwd()
  2523  	if err != nil {
  2524  		t.Fatal(err)
  2525  	}
  2526  
  2527  	if err := os.Chdir(tempDir); err != nil {
  2528  		t.Fatal(err)
  2529  	}
  2530  
  2531  	defer func() {
  2532  		if err := os.Chdir(wd); err != nil {
  2533  			t.Fatal(err)
  2534  		}
  2535  	}()
  2536  
  2537  	needFiles(t, root, []string{})
  2538  	blacklist := map[string]struct{}{
  2539  		"inet.c": {}, //TODO
  2540  		"math.c": {}, //TODO
  2541  	}
  2542  	var rq, res, ok int
  2543  	limit := runtime.GOMAXPROCS(0)
  2544  	limiter := make(chan struct{}, limit)
  2545  	success := make([]string, 0, 0)
  2546  	results := make(chan *runResult, limit)
  2547  	failed := map[string]struct{}{}
  2548  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2549  		if !strings.HasSuffix(pth, ".c") {
  2550  			return nil
  2551  		}
  2552  
  2553  		switch {
  2554  		case re != nil:
  2555  			if !re.MatchString(pth) {
  2556  				return nil
  2557  			}
  2558  		default:
  2559  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2560  				return nil
  2561  			}
  2562  		}
  2563  
  2564  	more:
  2565  		select {
  2566  		case r := <-results:
  2567  			res++
  2568  			<-limiter
  2569  			switch r.err.(type) {
  2570  			case nil:
  2571  				ok++
  2572  				success = append(success, filepath.Base(r.name))
  2573  				delete(failed, r.name)
  2574  			case skipErr:
  2575  				delete(failed, r.name)
  2576  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2577  			default:
  2578  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2579  			}
  2580  			goto more
  2581  		case limiter <- struct{}{}:
  2582  			rq++
  2583  			if *oTrace {
  2584  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2585  			}
  2586  			failed[pth] = struct{}{}
  2587  			go run(pth, false, false, true, results)
  2588  		}
  2589  		return nil
  2590  	})
  2591  	if err != nil {
  2592  		t.Fatal(err)
  2593  	}
  2594  	for res != rq {
  2595  		r := <-results
  2596  		res++
  2597  		<-limiter
  2598  		switch r.err.(type) {
  2599  		case nil:
  2600  			ok++
  2601  			success = append(success, filepath.Base(r.name))
  2602  			delete(failed, r.name)
  2603  		case skipErr:
  2604  			delete(failed, r.name)
  2605  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2606  		default:
  2607  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2608  		}
  2609  	}
  2610  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2611  	sort.Strings(success)
  2612  	for _, fpath := range success {
  2613  		g.w.Write([]byte(fpath))
  2614  		g.w.Write([]byte{'\n'})
  2615  	}
  2616  	if len(failed) == 0 {
  2617  		return
  2618  	}
  2619  
  2620  	var a []string
  2621  	for k := range failed {
  2622  		a = append(a, k)
  2623  	}
  2624  	sort.Strings(a)
  2625  	for _, v := range a {
  2626  		t.Logf("FAIL %s", v)
  2627  	}
  2628  }
  2629  
  2630  func TestSQLite(t *testing.T) {
  2631  	root := filepath.Join(testWD, filepath.FromSlash(sqliteDir))
  2632  	testSQLite(t, root)
  2633  }
  2634  
  2635  func testSQLite(t *testing.T, dir string) {
  2636  	const main = "main.go"
  2637  	wd, err := os.Getwd()
  2638  	if err != nil {
  2639  		t.Fatal(err)
  2640  	}
  2641  
  2642  	defer os.Chdir(wd)
  2643  
  2644  	temp, err := ioutil.TempDir("", "ccgo-test-")
  2645  	if err != nil {
  2646  		t.Fatal(err)
  2647  	}
  2648  
  2649  	switch {
  2650  	case *oKeep:
  2651  		t.Log(temp)
  2652  	default:
  2653  		defer os.RemoveAll(temp)
  2654  	}
  2655  
  2656  	if _, _, err := CopyDir(temp, dir, nil); err != nil {
  2657  		t.Fatal(err)
  2658  	}
  2659  
  2660  	if err := os.Chdir(temp); err != nil {
  2661  		t.Fatal(err)
  2662  	}
  2663  
  2664  	ccgoArgs := []string{
  2665  		"ccgo",
  2666  
  2667  		"-DHAVE_USLEEP",
  2668  		"-DLONGDOUBLE_TYPE=double",
  2669  		"-DSQLITE_DEBUG",
  2670  		"-DSQLITE_DEFAULT_MEMSTATUS=0",
  2671  		"-DSQLITE_ENABLE_DBPAGE_VTAB",
  2672  		"-DSQLITE_LIKE_DOESNT_MATCH_BLOBS",
  2673  		"-DSQLITE_MEMDEBUG",
  2674  		"-DSQLITE_THREADSAFE=0",
  2675  		"-D__attribute__(x)=", // bypass parser bug on windows/386
  2676  		"-export-fields", "F",
  2677  		"-ignore-unsupported-alignment",
  2678  		"-all-errors",
  2679  		"-err-trace",
  2680  		"-o", main,
  2681  		"-verify-structs",
  2682  		"shell.c",
  2683  		"sqlite3.c",
  2684  	}
  2685  	if runtime.GOARCH == "riscv64" {
  2686  		ccgoArgs = []string{
  2687  			"ccgo",
  2688  
  2689  			"-DHAVE_USLEEP",
  2690  			"-DLONGDOUBLE_TYPE=double",
  2691  			"-DSQLITE_DEBUG",
  2692  			"-DSQLITE_DEFAULT_MEMSTATUS=0",
  2693  			"-DSQLITE_ENABLE_DBPAGE_VTAB",
  2694  			"-DSQLITE_LIKE_DOESNT_MATCH_BLOBS",
  2695  			"-DSQLITE_MEMDEBUG",
  2696  			"-DSQLITE_THREADSAFE=0",
  2697  			"-D__attribute__(x)=", // bypass parser bug on windows/386
  2698  			"-export-fields", "F",
  2699  			"-ignore-unsupported-alignment",
  2700  			"-all-errors",
  2701  			"-err-trace",
  2702  			"-o", main,
  2703  			//TODO "-verify-structs",
  2704  			"shell.c",
  2705  			"sqlite3.c",
  2706  		}
  2707  	}
  2708  	if *oDebug {
  2709  		ccgoArgs = append(ccgoArgs, "-DSQLITE_DEBUG_OS_TRACE", "-DSQLITE_FORCE_OS_TRACE", "-DSQLITE_LOCK_TRACE")
  2710  	}
  2711  	if os.Getenv("GO111MODULE") != "off" {
  2712  		if out, err := Shell("go", "mod", "init", "example.com/ccgo/v3/lib/sqlite"); err != nil {
  2713  			t.Fatalf("%v\n%s", err, out)
  2714  		}
  2715  
  2716  		if out, err := Shell("go", "get", "modernc.org/libc"); err != nil {
  2717  			t.Fatalf("%v\n%s", err, out)
  2718  		}
  2719  	}
  2720  
  2721  	if !func() (r bool) {
  2722  		defer func() {
  2723  			if err := recover(); err != nil {
  2724  				if *oStackTrace {
  2725  					fmt.Printf("%s\n", stack())
  2726  				}
  2727  				if *oTrace {
  2728  					fmt.Println(err)
  2729  				}
  2730  				t.Errorf("%v", err)
  2731  				r = false
  2732  			}
  2733  			if *oTraceF {
  2734  				b, _ := ioutil.ReadFile(main)
  2735  				fmt.Printf("\n----\n%s\n----\n", b)
  2736  			}
  2737  		}()
  2738  
  2739  		if err := NewTask(ccgoArgs, nil, nil).Main(); err != nil {
  2740  			if *oTrace {
  2741  				fmt.Println(err)
  2742  			}
  2743  			err = cpp(*oCpp, ccgoArgs, err)
  2744  			t.Errorf("%v", err)
  2745  			return false
  2746  		}
  2747  
  2748  		return true
  2749  	}() {
  2750  		return
  2751  	}
  2752  
  2753  	shell := "./shell"
  2754  	if runtime.GOOS == "windows" {
  2755  		shell = "./shell.exe"
  2756  	}
  2757  	args := []string{"build"}
  2758  	if s := *oXTags; s != "" {
  2759  		args = append(args, "-tags", s)
  2760  	}
  2761  	args = append(args, "-o", shell, main)
  2762  	if out, err := exec.Command("go", args...).CombinedOutput(); err != nil {
  2763  		s := strings.TrimSpace(string(out))
  2764  		if s != "" {
  2765  			s += "\n"
  2766  		}
  2767  		t.Errorf("%s%v", s, err)
  2768  		return
  2769  	}
  2770  
  2771  	var out []byte
  2772  	switch {
  2773  	case *oDebug:
  2774  		out, err = exec.Command(shell, "tmp", ".log stdout", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput()
  2775  	default:
  2776  		out, err = exec.Command(shell, "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput()
  2777  	}
  2778  	if err != nil {
  2779  		if *oTrace {
  2780  			fmt.Printf("%s\n%s\n", out, err)
  2781  		}
  2782  		t.Errorf("%s\n%v", out, err)
  2783  		return
  2784  	}
  2785  
  2786  	if g, e := strings.TrimSpace(string(out)), "462"; g != e {
  2787  		t.Errorf("got: %s\nexp: %s", g, e)
  2788  	}
  2789  	if *oTraceO {
  2790  		fmt.Printf("%s\n", out)
  2791  	}
  2792  
  2793  	if out, err = exec.Command(shell, "tmp", "select 13*i from t;").CombinedOutput(); err != nil {
  2794  		if *oTrace {
  2795  			fmt.Printf("%s\n%s\n", out, err)
  2796  		}
  2797  		t.Errorf("%v", err)
  2798  		return
  2799  	}
  2800  
  2801  	if g, e := strings.TrimSpace(string(out)), "546"; g != e {
  2802  		t.Errorf("got: %s\nexp: %s", g, e)
  2803  	}
  2804  	if *oTraceO {
  2805  		fmt.Printf("%s\n", out)
  2806  	}
  2807  }
  2808  
  2809  func TestBug(t *testing.T) {
  2810  	const root = "/ccgo/bug"
  2811  	g := newGolden(t, fmt.Sprintf("testdata/bug_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  2812  
  2813  	defer g.close()
  2814  
  2815  	mustEmptyDir(t, tempDir, keep)
  2816  	wd, err := os.Getwd()
  2817  	if err != nil {
  2818  		t.Fatal(err)
  2819  	}
  2820  
  2821  	if err := os.Chdir(tempDir); err != nil {
  2822  		t.Fatal(err)
  2823  	}
  2824  
  2825  	defer func() {
  2826  		if err := os.Chdir(wd); err != nil {
  2827  			t.Fatal(err)
  2828  		}
  2829  	}()
  2830  
  2831  	blacklist := map[string]struct{}{}
  2832  	switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) {
  2833  	case "linux/s390x":
  2834  		blacklist["bitfield.c"] = struct{}{} //TODO
  2835  	}
  2836  	var rq, res, ok int
  2837  	limit := runtime.GOMAXPROCS(0)
  2838  	limiter := make(chan struct{}, limit)
  2839  	success := make([]string, 0, 0)
  2840  	results := make(chan *runResult, limit)
  2841  	failed := map[string]struct{}{}
  2842  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2843  		if !strings.HasSuffix(pth, ".c") {
  2844  			return nil
  2845  		}
  2846  
  2847  		switch {
  2848  		case re != nil:
  2849  			if !re.MatchString(pth) {
  2850  				return nil
  2851  			}
  2852  		default:
  2853  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2854  				return nil
  2855  			}
  2856  		}
  2857  
  2858  	more:
  2859  		select {
  2860  		case r := <-results:
  2861  			res++
  2862  			<-limiter
  2863  			switch r.err.(type) {
  2864  			case nil:
  2865  				ok++
  2866  				success = append(success, filepath.Base(r.name))
  2867  				delete(failed, r.name)
  2868  			case skipErr:
  2869  				delete(failed, r.name)
  2870  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2871  			default:
  2872  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2873  			}
  2874  			goto more
  2875  		case limiter <- struct{}{}:
  2876  			rq++
  2877  			if *oTrace {
  2878  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2879  			}
  2880  			failed[pth] = struct{}{}
  2881  			go run(pth, false, false, false, results)
  2882  		}
  2883  		return nil
  2884  	})
  2885  	if err != nil {
  2886  		t.Fatal(err)
  2887  	}
  2888  	for res != rq {
  2889  		r := <-results
  2890  		res++
  2891  		<-limiter
  2892  		switch r.err.(type) {
  2893  		case nil:
  2894  			ok++
  2895  			success = append(success, filepath.Base(r.name))
  2896  			delete(failed, r.name)
  2897  		case skipErr:
  2898  			delete(failed, r.name)
  2899  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2900  		default:
  2901  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2902  		}
  2903  	}
  2904  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2905  	sort.Strings(success)
  2906  	for _, fpath := range success {
  2907  		g.w.Write([]byte(fpath))
  2908  		g.w.Write([]byte{'\n'})
  2909  	}
  2910  	if len(failed) == 0 {
  2911  		return
  2912  	}
  2913  
  2914  	var a []string
  2915  	for k := range failed {
  2916  		a = append(a, k)
  2917  	}
  2918  	sort.Strings(a)
  2919  	for _, v := range a {
  2920  		t.Logf("FAIL %s", v)
  2921  	}
  2922  }
  2923  
  2924  func TestCSmith(t *testing.T) {
  2925  	gcc := os.Getenv("CC")
  2926  	if gcc == "" {
  2927  		gcc = "gcc"
  2928  	}
  2929  	gcc, err := exec.LookPath(gcc)
  2930  	if err != nil {
  2931  		t.Skip(err)
  2932  		return
  2933  	}
  2934  
  2935  	if testing.Short() {
  2936  		t.Skip("skipped: -short")
  2937  	}
  2938  
  2939  	csmith, err := exec.LookPath("csmith")
  2940  	if err != nil {
  2941  		t.Skip(err)
  2942  		return
  2943  	}
  2944  	binaryName := filepath.FromSlash("./a.out")
  2945  	mainName := filepath.FromSlash("main.go")
  2946  	wd, err := os.Getwd()
  2947  	if err != nil {
  2948  		t.Fatal(err)
  2949  	}
  2950  
  2951  	defer os.Chdir(wd)
  2952  
  2953  	temp, err := ioutil.TempDir("", "ccgo-test-")
  2954  	if err != nil {
  2955  		t.Fatal(err)
  2956  	}
  2957  
  2958  	defer os.RemoveAll(temp)
  2959  
  2960  	if err := os.Chdir(temp); err != nil {
  2961  		t.Fatal(err)
  2962  	}
  2963  
  2964  	if os.Getenv("GO111MODULE") != "off" {
  2965  		if out, err := Shell("go", "mod", "init", "example.com/ccgo/v3/lib/csmith"); err != nil {
  2966  			t.Fatalf("%v\n%s", err, out)
  2967  		}
  2968  
  2969  		if out, err := Shell("go", "get", "modernc.org/libc"); err != nil {
  2970  			t.Fatalf("%v\n%s", err, out)
  2971  		}
  2972  	}
  2973  
  2974  	fixedBugs := []string{
  2975  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1906742816",
  2976  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 612971101",
  2977  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 3629008936",
  2978  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4130344133",
  2979  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3130410542",
  2980  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1833258637",
  2981  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3126091077",
  2982  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324",
  2983  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3043990076",
  2984  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2517344771",
  2985  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 56498550",
  2986  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3645367888",
  2987  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 169375684",
  2988  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3578720023",
  2989  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1885311141",
  2990  		"--no-bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3720922579",
  2991  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 241244373",
  2992  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 517639208",
  2993  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324",
  2994  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2876930815",
  2995  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3365074920",
  2996  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3329111231",
  2997  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2648215054",
  2998  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3919255949",
  2999  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 890611563",
  3000  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4101947480",
  3001  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4058772172",
  3002  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2273393378",
  3003  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3100949894",
  3004  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 15739796933983044010", //TODO fails on linux/s390x
  3005  
  3006  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 963985971",
  3007  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3363122597",
  3008  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4146870674",
  3009  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1236173074", //TODO fails on darwin/amd64
  3010  	}
  3011  	ch := time.After(*oCSmith)
  3012  	t0 := time.Now()
  3013  	var files, ok int
  3014  	var size int64
  3015  	var re *regexp.Regexp
  3016  	if s := *oRE; s != "" {
  3017  		re = regexp.MustCompile(s)
  3018  	}
  3019  out:
  3020  	for i := 0; ; i++ {
  3021  		extra := ""
  3022  		var args string
  3023  		switch {
  3024  		case i < len(fixedBugs):
  3025  			if re != nil && !re.MatchString(fixedBugs[i]) {
  3026  				continue
  3027  			}
  3028  
  3029  			args += fixedBugs[i]
  3030  			a := strings.Split(fixedBugs[i], " ")
  3031  			extra = strings.Join(a[len(a)-2:], " ")
  3032  			t.Log(args)
  3033  		default:
  3034  			select {
  3035  			case <-ch:
  3036  				break out
  3037  			default:
  3038  			}
  3039  
  3040  			args += csmithDefaultArgs
  3041  		}
  3042  		csOut, err := exec.Command(csmith, strings.Split(args, " ")...).Output()
  3043  		if err != nil {
  3044  			t.Fatalf("%v\n%s", err, csOut)
  3045  		}
  3046  
  3047  		if fn := *oBlackBox; fn != "" {
  3048  			if err := ioutil.WriteFile(fn, csOut, 0660); err != nil {
  3049  				t.Fatal(err)
  3050  			}
  3051  		}
  3052  
  3053  		if err := ioutil.WriteFile("main.c", csOut, 0660); err != nil {
  3054  			t.Fatal(err)
  3055  		}
  3056  
  3057  		csp := fmt.Sprintf("-I%s", filepath.FromSlash("/usr/include/csmith"))
  3058  		if s := os.Getenv("CSMITH_PATH"); s != "" {
  3059  			csp = fmt.Sprintf("-I%s", s)
  3060  		}
  3061  
  3062  		ccOut, err := exec.Command(gcc, "-o", binaryName, "main.c", csp).CombinedOutput()
  3063  		if err != nil {
  3064  			t.Logf("%s\n%s\ncc: %v", extra, ccOut, err)
  3065  			continue
  3066  		}
  3067  
  3068  		binOutA, err := func() ([]byte, error) {
  3069  			ctx, cancel := context.WithTimeout(context.Background(), execTimeout)
  3070  			defer cancel()
  3071  
  3072  			return exec.CommandContext(ctx, binaryName).CombinedOutput()
  3073  		}()
  3074  		if err != nil {
  3075  			continue
  3076  		}
  3077  
  3078  		size += int64(len(csOut))
  3079  
  3080  		if err := os.Remove(binaryName); err != nil {
  3081  			t.Fatal(err)
  3082  		}
  3083  
  3084  		files++
  3085  		var stdout, stderr bytes.Buffer
  3086  		j := NewTask([]string{
  3087  			"ccgo",
  3088  
  3089  			"-o", mainName,
  3090  			"-verify-structs",
  3091  			"main.c",
  3092  			csp,
  3093  		}, &stdout, &stderr)
  3094  		j.cfg.MaxSourceLine = 1 << 20
  3095  
  3096  		func() {
  3097  
  3098  			defer func() {
  3099  				if err := recover(); err != nil {
  3100  					t.Errorf("%s\n%s\nccgo: %s\n%s\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), debug.Stack())
  3101  					t.Fatal(err)
  3102  				}
  3103  			}()
  3104  
  3105  			if err := j.Main(); err != nil || stdout.Len() != 0 {
  3106  				t.Errorf("%s\n%s\nccgo: %s\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes())
  3107  				t.Fatal(err)
  3108  			}
  3109  		}()
  3110  
  3111  		binOutB, err := func() ([]byte, error) {
  3112  			ctx, cancel := context.WithTimeout(context.Background(), execTimeout)
  3113  			defer cancel()
  3114  
  3115  			return exec.CommandContext(ctx, "go", "run", "-tags=libc.memgrind", mainName).CombinedOutput()
  3116  		}()
  3117  		if err != nil {
  3118  			t.Errorf("%s\n%s\n%s\nccgo: %v", extra, csOut, binOutB, err)
  3119  			break
  3120  		}
  3121  
  3122  		if g, e := binOutB, binOutA; !bytes.Equal(g, e) {
  3123  			t.Errorf("%s\n%s\nccgo: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e)
  3124  			break
  3125  		}
  3126  
  3127  		ok++
  3128  		if *oTrace {
  3129  			fmt.Fprintln(os.Stderr, time.Since(t0), files, ok)
  3130  		}
  3131  
  3132  		if err := os.Remove(mainName); err != nil {
  3133  			t.Fatal(err)
  3134  		}
  3135  	}
  3136  	d := time.Since(t0)
  3137  	t.Logf("files %v, bytes %v, ok %v in %v", h(files), h(size), h(ok), d)
  3138  }
  3139  
  3140  func dumpInitializer(s []*cc.Initializer) string {
  3141  	if len(s) == 0 {
  3142  		return "<empty>"
  3143  	}
  3144  	var a []string
  3145  	for _, v := range s {
  3146  		var s string
  3147  		if f := v.Field; f != nil {
  3148  			s = fmt.Sprintf("fld %q bitfield %v bitoff %2d", f.Name(), f.IsBitField(), f.BitFieldOffset())
  3149  		}
  3150  		a = append(a, fmt.Sprintf("%v: off %#04x val %v %s", v.Position(), v.Offset, v.AssignmentExpression.Operand.Value(), s))
  3151  	}
  3152  	return strings.Join(a, "\n")
  3153  }