modernc.org/gocc@v0.0.1/all_test.go (about)

     1  // Copyright 2019 The GOCC 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  //TODO gcc 4.7
     6  
     7  package main // import "modernc.org/gocc"
     8  
     9  import (
    10  	"archive/tar"
    11  	"archive/zip"
    12  	"bufio"
    13  	"bytes"
    14  	"compress/bzip2"
    15  	"compress/gzip"
    16  	"context"
    17  	"encoding/hex"
    18  	"flag"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"os"
    24  	"os/exec"
    25  	"path"
    26  	"path/filepath"
    27  	"regexp"
    28  	"runtime"
    29  	"runtime/debug"
    30  	"sort"
    31  	"strings"
    32  	"testing"
    33  	"time"
    34  
    35  	"github.com/dustin/go-humanize"
    36  	"github.com/google/go-cmp/cmp"
    37  	"modernc.org/cc/v3"
    38  )
    39  
    40  func caller(s string, va ...interface{}) {
    41  	if s == "" {
    42  		s = strings.Repeat("%v ", len(va))
    43  	}
    44  	_, fn, fl, _ := runtime.Caller(2)
    45  	fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
    46  	fmt.Fprintf(os.Stderr, s, va...)
    47  	fmt.Fprintln(os.Stderr)
    48  	_, fn, fl, _ = runtime.Caller(1)
    49  	fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
    50  	fmt.Fprintln(os.Stderr)
    51  	os.Stderr.Sync()
    52  }
    53  
    54  func dbg(s string, va ...interface{}) {
    55  	if s == "" {
    56  		s = strings.Repeat("%v ", len(va))
    57  	}
    58  	_, fn, fl, _ := runtime.Caller(1)
    59  	fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
    60  	fmt.Fprintf(os.Stderr, s, va...)
    61  	fmt.Fprintln(os.Stderr)
    62  	os.Stderr.Sync()
    63  }
    64  
    65  func TODO(...interface{}) string { //TODOOK
    66  	_, fn, fl, _ := runtime.Caller(1)
    67  	return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK
    68  }
    69  
    70  func stack() string { return string(debug.Stack()) }
    71  
    72  func use(...interface{}) {}
    73  
    74  func init() {
    75  	use(caller, dbg, TODO, stack, dumpLayout) //TODOOK
    76  }
    77  
    78  // ----------------------------------------------------------------------------
    79  
    80  var (
    81  	oBlackBox   = flag.String("blackbox", "", "Record CSmith file to this file")
    82  	oCSmith     = flag.Duration("csmith", time.Minute, "")
    83  	oCertN      = flag.Int("certN", 5, "")
    84  	oDev        = flag.Bool("dev", false, "Enable developer tests/downloads.")
    85  	oDownload   = flag.Bool("download", false, "Download missing testdata. Add -dev to download also 100+ MB of developer resources.")
    86  	oEdit       = flag.Bool("edit", false, "")
    87  	oFF         = flag.Bool("ff", false, "Fail fast")
    88  	oM32        = flag.Bool("m32", false, "")
    89  	oRE         = flag.String("re", "", "")
    90  	oStackTrace = flag.Bool("trcstack", false, "")
    91  	oTrace      = flag.Bool("trc", false, "Print tested paths.")
    92  	oTraceO     = flag.Bool("trco", false, "Print test output")
    93  
    94  	csmithDefaultArgs = strings.Join([]string{
    95  		"--bitfields",                     // --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default).
    96  		"--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.
    97  		"--no-const-pointers", // --const-pointers | --no-const-pointers: enable | disable const pointers (enabled by default).
    98  		"--no-consts",         // --consts | --no-consts: enable | disable const qualifier (enabled by default).
    99  		"--no-packed-struct",  // --packed-struct | --no-packed-struct: enable | disable packed structs by adding #pragma pack(1) before struct definition (disabled by default).
   100  		// "--no-safe-math",         // --safe-math | --no-safe-math: Emit safe math wrapper functions (enabled by default).
   101  		"--no-volatile-pointers", // --volatile-pointers | --no-volatile-pointers: enable | disable volatile pointers (enabled by default).
   102  		"--no-volatiles",         // --volatiles | --no-volatiles: enable | disable volatiles (enabled by default).
   103  		"--paranoid",             // --paranoid | --no-paranoid: enable | disable pointer-related assertions (disabled by default).
   104  	}, " ")
   105  
   106  	downloads = []struct {
   107  		dir, url string
   108  		sz       int
   109  		dev      bool
   110  	}{
   111  		{gccDir, "http://mirror.koddos.net/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.gz", 118000, true},
   112  		{sqliteDir, "https://www.sqlite.org/2019/sqlite-amalgamation-3300100.zip", 2400, false},
   113  		{tccDir, "http://download.savannah.gnu.org/releases/tinycc/tcc-0.9.27.tar.bz2", 620, false},
   114  	}
   115  
   116  	gccDir    = filepath.FromSlash("testdata/gcc-9.1.0")
   117  	sqliteDir = filepath.FromSlash("testdata/sqlite-amalgamation-3300100")
   118  	tccDir    = filepath.FromSlash("testdata/tcc-0.9.27")
   119  	testWD    string
   120  
   121  	gccTestDecls = cc.Source{Name: "<gcc-test-builtin>", Value: `
   122  char *strchr(const char *s, int c);
   123  char *strcpy(char *dest, const char *src);
   124  double copysign(double x, double y);
   125  double fabs(double x);
   126  float copysignf(float x, float y);
   127  int abs(int j);
   128  int ffs(int i);
   129  int isprint(int c);
   130  int memcmp(const void *s1, const void *s2, size_t n);
   131  int printf(const char *format, ...);
   132  int snprintf(char *str, size_t size, const char *format, ...);
   133  int sprintf(char *str, const char *format, ...);
   134  int strcmp(const char *s1, const char *s2);
   135  size_t strlen(const char *s);
   136  void *malloc(size_t size);
   137  void *memcpy(void *dest, const void *src, size_t n);
   138  void *memset(void *s, int c, size_t n);
   139  void abort(void);
   140  void exit(int status);
   141  void free(void *ptr);
   142  	`}
   143  )
   144  
   145  func TestMain(m *testing.M) {
   146  	isTesting = true
   147  
   148  	defer func() {
   149  		os.Exit(m.Run())
   150  	}()
   151  
   152  	flag.BoolVar(&oQuiet, "q", false, "")
   153  	flag.BoolVar(&oTODO, "todo", false, "")
   154  	flag.BoolVar(&traceIL, "il", false, "print generated IL")
   155  
   156  	flag.Parse()
   157  	var err error
   158  	if testWD, err = os.Getwd(); err != nil {
   159  		panic("Cannot determine working dir: " + err.Error())
   160  	}
   161  
   162  	if *oDownload {
   163  		download()
   164  	}
   165  }
   166  
   167  func download() {
   168  	tmp, err := ioutil.TempDir("", "")
   169  	if err != nil {
   170  		fmt.Fprintf(os.Stderr, "%s\n", err)
   171  		return
   172  	}
   173  
   174  	defer os.RemoveAll(tmp)
   175  
   176  	for _, v := range downloads {
   177  		dir := filepath.FromSlash(v.dir)
   178  		root := filepath.Dir(v.dir)
   179  		fi, err := os.Stat(dir)
   180  		switch {
   181  		case err == nil:
   182  			if !fi.IsDir() {
   183  				fmt.Fprintf(os.Stderr, "expected %s to be a directory\n", dir)
   184  			}
   185  			continue
   186  		default:
   187  			if !os.IsNotExist(err) {
   188  				fmt.Fprintf(os.Stderr, "%s", err)
   189  				continue
   190  			}
   191  
   192  			if v.dev && !*oDev {
   193  				fmt.Printf("Not downloading (no -dev) %v MB from %s\n", float64(v.sz)/1000, v.url)
   194  				continue
   195  			}
   196  
   197  		}
   198  
   199  		if err := func() error {
   200  			fmt.Printf("Downloading %v MB from %s\n", float64(v.sz)/1000, v.url)
   201  			resp, err := http.Get(v.url)
   202  			if err != nil {
   203  				return err
   204  			}
   205  
   206  			defer resp.Body.Close()
   207  
   208  			base := filepath.Base(v.url)
   209  			name := filepath.Join(tmp, base)
   210  			f, err := os.Create(name)
   211  			if err != nil {
   212  				return err
   213  			}
   214  
   215  			defer os.Remove(name)
   216  
   217  			n, err := io.Copy(f, resp.Body)
   218  			if err != nil {
   219  				return err
   220  			}
   221  
   222  			if _, err := f.Seek(0, io.SeekStart); err != nil {
   223  				return err
   224  			}
   225  
   226  			switch {
   227  			case strings.HasSuffix(base, ".tar.bz2"):
   228  				b2r := bzip2.NewReader(bufio.NewReader(f))
   229  				tr := tar.NewReader(b2r)
   230  				for {
   231  					hdr, err := tr.Next()
   232  					if err != nil {
   233  						if err != io.EOF {
   234  							return err
   235  						}
   236  
   237  						return nil
   238  					}
   239  
   240  					switch hdr.Typeflag {
   241  					case tar.TypeDir:
   242  						if err = os.MkdirAll(filepath.Join(root, hdr.Name), 0770); err != nil {
   243  							return err
   244  						}
   245  					case tar.TypeReg, tar.TypeRegA:
   246  						f, err := os.OpenFile(filepath.Join(root, hdr.Name), os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode))
   247  						if err != nil {
   248  							return err
   249  						}
   250  
   251  						w := bufio.NewWriter(f)
   252  						if _, err = io.Copy(w, tr); err != nil {
   253  							return err
   254  						}
   255  
   256  						if err := w.Flush(); err != nil {
   257  							return err
   258  						}
   259  
   260  						if err := f.Close(); err != nil {
   261  							return err
   262  						}
   263  					default:
   264  						return fmt.Errorf("unexpected tar header typeflag %#02x", hdr.Typeflag)
   265  					}
   266  				}
   267  			case strings.HasSuffix(base, ".tar.gz"):
   268  				return untar(root, bufio.NewReader(f))
   269  			case strings.HasSuffix(base, ".zip"):
   270  				r, err := zip.NewReader(f, n)
   271  				if err != nil {
   272  					return err
   273  				}
   274  
   275  				for _, f := range r.File {
   276  					fi := f.FileInfo()
   277  					if fi.IsDir() {
   278  						if err := os.MkdirAll(filepath.Join(root, f.Name), 0770); err != nil {
   279  							return err
   280  						}
   281  
   282  						continue
   283  					}
   284  
   285  					if err := func() error {
   286  						rc, err := f.Open()
   287  						if err != nil {
   288  							return err
   289  						}
   290  
   291  						defer rc.Close()
   292  
   293  						dname := filepath.Join(root, f.Name)
   294  						g, err := os.Create(dname)
   295  						if err != nil {
   296  							return err
   297  						}
   298  
   299  						defer g.Close()
   300  
   301  						n, err = io.Copy(g, rc)
   302  						return err
   303  					}(); err != nil {
   304  						return err
   305  					}
   306  				}
   307  				return nil
   308  			}
   309  			panic("internal error") //TODOOK
   310  		}(); err != nil {
   311  			fmt.Fprintln(os.Stderr, err)
   312  		}
   313  	}
   314  }
   315  
   316  func TestTCC(t *testing.T) {
   317  	root := filepath.Join(testWD, filepath.FromSlash(tccDir))
   318  	if _, err := os.Stat(root); err != nil {
   319  		t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root)
   320  	}
   321  
   322  	g := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
   323  
   324  	defer g.close()
   325  
   326  	todos = map[todoPos]int{}
   327  	var files, ok int
   328  	if *oEdit {
   329  		defer func() {
   330  			fmt.Printf("TCC files %s, ok %s\n", h(files), h(ok))
   331  		}()
   332  	}
   333  	const dir = "tests/tests2"
   334  	t.Run("noOpt", func(t *testing.T) {
   335  		f, o := testTCCExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false)
   336  		files += f
   337  		ok += o
   338  	})
   339  	t.Logf("files %s, ok %s", h(files), h(ok))
   340  	if !oQuiet {
   341  		dumpTODOs(t)
   342  	}
   343  
   344  	g2 := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH))
   345  
   346  	defer g2.close()
   347  	todos = map[todoPos]int{}
   348  	files = 0
   349  	ok = 0
   350  	t.Run("opt", func(t *testing.T) {
   351  		f, o := testTCCExec(g2.w, t, filepath.Join(root, filepath.FromSlash(dir)), true)
   352  		files += f
   353  		ok += o
   354  	})
   355  	t.Logf("files %s, ok %s", h(files), h(ok))
   356  	if !oQuiet {
   357  		dumpTODOs(t)
   358  	}
   359  }
   360  
   361  type golden struct {
   362  	t *testing.T
   363  	f *os.File
   364  	w *bufio.Writer
   365  }
   366  
   367  func newGolden(t *testing.T, fn string) *golden {
   368  	f, err := os.Create(filepath.FromSlash(fn))
   369  	if err != nil {
   370  		t.Fatal(err)
   371  	}
   372  
   373  	w := bufio.NewWriter(f)
   374  	return &golden{t, f, w}
   375  }
   376  
   377  func (g *golden) close() {
   378  	if err := g.w.Flush(); err != nil {
   379  		g.t.Fatal(err)
   380  	}
   381  
   382  	if err := g.f.Close(); err != nil {
   383  		g.t.Fatal(err)
   384  	}
   385  }
   386  
   387  func fail(t *testing.T, s string, args ...interface{}) {
   388  	if *oFF {
   389  		t.Fatalf(s, args...)
   390  	}
   391  
   392  	if !oQuiet {
   393  		t.Errorf(s, args...)
   394  	}
   395  }
   396  
   397  func testTCCExec(w io.Writer, t *testing.T, dir string, optimize bool) (files, ok int) {
   398  	const binaryName = "a.out"
   399  	blacklist := map[string]struct{}{
   400  		"34_array_assignment.c":    {}, // gcc: 16:6: error: assignment to expression with array type
   401  		"60_errors_and_warnings.c": {}, // Not a standalone test. gcc fails.
   402  		"93_integer_promotion.c":   {}, // The expected output does not agree with gcc.
   403  		"95_bitfields.c":           {}, // Included from 95_bitfields_ms.c
   404  		"95_bitfields_ms.c":        {}, // The expected output does not agree with gcc.
   405  		"96_nodata_wanted.c":       {}, // Not a standalone test. gcc fails.
   406  		"99_fastcall.c":            {}, // 386 only
   407  
   408  		"73_arm64.c":                {}, //TODO struct varargs, not supported by QBE
   409  		"75_array_in_struct_init.c": {}, //TODO flat struct initializer
   410  		"80_flexarray.c":            {}, //TODO Flexible array member
   411  		"85_asm-outside-function.c": {}, //TODO
   412  		"90_struct-init.c":          {}, //TODO cc ... in designator
   413  		"94_generic.c":              {}, //TODO cc _Generic
   414  		"98_al_ax_extend.c":         {}, //TODO
   415  	}
   416  	wd, err := os.Getwd()
   417  	if err != nil {
   418  		t.Fatal(err)
   419  	}
   420  
   421  	defer os.Chdir(wd)
   422  
   423  	temp, err := ioutil.TempDir("", "gocc-test-")
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  
   428  	defer os.RemoveAll(temp)
   429  
   430  	if err := os.Chdir(temp); err != nil {
   431  		t.Fatal(err)
   432  	}
   433  
   434  	var re *regexp.Regexp
   435  	if s := *oRE; s != "" {
   436  		re = regexp.MustCompile(s)
   437  	}
   438  
   439  	if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
   440  		if err != nil {
   441  			if os.IsNotExist(err) {
   442  				err = nil
   443  			}
   444  			return err
   445  		}
   446  
   447  		if info.IsDir() {
   448  			return skipDir(path)
   449  		}
   450  
   451  		if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 {
   452  			return nil
   453  		}
   454  
   455  		if _, ok := blacklist[filepath.Base(path)]; ok {
   456  			return nil
   457  		}
   458  
   459  		files++
   460  
   461  		if re != nil && !re.MatchString(path) {
   462  			return nil
   463  		}
   464  
   465  		if *oTrace {
   466  			fmt.Fprintln(os.Stderr, files, ok, path)
   467  		}
   468  
   469  		if err := os.Remove(binaryName); err != nil && !os.IsNotExist(err) {
   470  			return err
   471  		}
   472  
   473  		goccArgs := []string{"gocc", "-o", binaryName, "-Dasm=__asm__", "-w"}
   474  		var args []string
   475  		switch base := filepath.Base(path); base {
   476  		case
   477  			"22_floating_point.c",
   478  			"24_math_library.c":
   479  
   480  			goccArgs = append(goccArgs, "-lm")
   481  		case "31_args.c":
   482  			args = []string{"arg1", "arg2", "arg3", "arg4", "arg5"}
   483  		case "46_grep.c":
   484  			if err := copyFile(path, filepath.Join(temp, base)); err != nil {
   485  				return err
   486  			}
   487  
   488  			args = []string{`[^* ]*[:a:d: ]+\:\*-/: $`, base}
   489  		}
   490  
   491  		if !func() (r bool) {
   492  			defer func() {
   493  				if err := recover(); err != nil {
   494  					if *oStackTrace {
   495  						fmt.Printf("%s\n", stack())
   496  					}
   497  					if *oTrace {
   498  						fmt.Println(err)
   499  					}
   500  					if !oQuiet {
   501  						fail(t, "%s: %v", path, err)
   502  					}
   503  					r = false
   504  				}
   505  			}()
   506  
   507  			goccArgs = append(goccArgs, path)
   508  			switch base := filepath.Base(path); base {
   509  			case
   510  				"22_floating_point.c",
   511  				"24_math_library.c":
   512  
   513  				goccArgs = append(goccArgs, "-lm")
   514  			}
   515  			if _, err := execute(goccArgs, optimize); err != nil {
   516  				if *oTrace {
   517  					fmt.Println(err)
   518  				}
   519  				if !oQuiet {
   520  					fail(t, "%s: %v", path, err)
   521  				}
   522  				return false
   523  			}
   524  
   525  			return true
   526  		}() {
   527  			return nil
   528  		}
   529  
   530  		out, err := exec.Command("./"+binaryName, args...).CombinedOutput()
   531  		if err != nil {
   532  			if *oTrace {
   533  				fmt.Println(err)
   534  			}
   535  			t.Errorf("%v: %v", path, err)
   536  			return nil
   537  		}
   538  
   539  		if *oTraceO {
   540  			fmt.Printf("%s\n", out)
   541  		}
   542  		exp, err := ioutil.ReadFile(noExt(path) + ".expect")
   543  		if err != nil {
   544  			if os.IsNotExist(err) {
   545  				fmt.Fprintln(w, filepath.Base(path))
   546  				ok++
   547  				return nil
   548  			}
   549  
   550  			return err
   551  		}
   552  
   553  		out = trim(out)
   554  		exp = trim(exp)
   555  
   556  		switch base := filepath.Base(path); base {
   557  		case "70_floating_point_literals.c": //TODO TCC binary extension
   558  			a := strings.Split(string(exp), "\n")
   559  			exp = []byte(strings.Join(a[:35], "\n"))
   560  		}
   561  
   562  		if !bytes.Equal(out, exp) {
   563  			if *oTrace {
   564  				fmt.Println(err)
   565  			}
   566  			t.Errorf("%v: %s\nout\n%s\nexp\n%s", path, cmp.Diff(string(exp), string(out)), out, exp)
   567  			return nil
   568  		}
   569  
   570  		fmt.Fprintln(w, filepath.Base(path))
   571  		ok++
   572  		return nil
   573  	}); err != nil {
   574  		fail(t, "%v", err)
   575  	}
   576  	return files, ok
   577  }
   578  
   579  func TestTCCGo(t *testing.T) {
   580  	root := filepath.Join(testWD, filepath.FromSlash(tccDir))
   581  	if _, err := os.Stat(root); err != nil {
   582  		t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root)
   583  	}
   584  
   585  	g := newGolden(t, fmt.Sprintf("testdata/tcc_go_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
   586  
   587  	defer g.close()
   588  
   589  	todos = map[todoPos]int{}
   590  	var files, ok int
   591  	if *oEdit {
   592  		defer func() {
   593  			fmt.Printf("TCC files %s, ok %s\n", h(files), h(ok))
   594  		}()
   595  	}
   596  	const dir = "tests/tests2"
   597  	f, o := testTCCGoExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false)
   598  	files += f
   599  	ok += o
   600  	t.Logf("files %s, ok %s", h(files), h(ok))
   601  	if !oQuiet {
   602  		dumpTODOs(t)
   603  	}
   604  }
   605  
   606  func testTCCGoExec(w io.Writer, t *testing.T, dir string, optimize bool) (files, ok int) {
   607  	const main = "main.go"
   608  	blacklist := map[string]struct{}{
   609  		"34_array_assignment.c":    {}, // gcc: 16:6: error: assignment to expression with array type
   610  		"60_errors_and_warnings.c": {}, // Not a standalone test. gcc fails.
   611  		"93_integer_promotion.c":   {}, // The expected output does not agree with gcc.
   612  		"95_bitfields.c":           {}, // Included from 95_bitfields_ms.c
   613  		"95_bitfields_ms.c":        {}, // The expected output does not agree with gcc.
   614  		"96_nodata_wanted.c":       {}, // Not a standalone test. gcc fails.
   615  		"99_fastcall.c":            {}, // 386 only
   616  
   617  		"40_stdio.c":                {}, //TODO
   618  		"42_function_pointer.c":     {}, //TODO
   619  		"46_grep.c":                 {}, //TODO
   620  		"73_arm64.c":                {}, //TODO struct varargs, not supported by QBE
   621  		"75_array_in_struct_init.c": {}, //TODO flat struct initializer
   622  		"80_flexarray.c":            {}, //TODO Flexible array member
   623  		"85_asm-outside-function.c": {}, //TODO
   624  		"90_struct-init.c":          {}, //TODO cc ... in designator
   625  		"94_generic.c":              {}, //TODO cc _Generic
   626  		"98_al_ax_extend.c":         {}, //TODO
   627  	}
   628  	wd, err := os.Getwd()
   629  	if err != nil {
   630  		t.Fatal(err)
   631  	}
   632  
   633  	defer os.Chdir(wd)
   634  
   635  	temp, err := ioutil.TempDir("", "gocc-test-")
   636  	if err != nil {
   637  		t.Fatal(err)
   638  	}
   639  
   640  	defer os.RemoveAll(temp)
   641  
   642  	if err := os.Chdir(temp); err != nil {
   643  		t.Fatal(err)
   644  	}
   645  
   646  	var re *regexp.Regexp
   647  	if s := *oRE; s != "" {
   648  		re = regexp.MustCompile(s)
   649  	}
   650  
   651  	if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
   652  		if err != nil {
   653  			if os.IsNotExist(err) {
   654  				err = nil
   655  			}
   656  			return err
   657  		}
   658  
   659  		if info.IsDir() {
   660  			return skipDir(path)
   661  		}
   662  
   663  		if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 {
   664  			return nil
   665  		}
   666  
   667  		if _, ok := blacklist[filepath.Base(path)]; ok {
   668  			return nil
   669  		}
   670  
   671  		files++
   672  
   673  		if re != nil && !re.MatchString(path) {
   674  			return nil
   675  		}
   676  
   677  		if *oTrace {
   678  			fmt.Fprintln(os.Stderr, files, ok, path)
   679  		}
   680  
   681  		if err := os.Remove(main); err != nil && !os.IsNotExist(err) {
   682  			return err
   683  		}
   684  
   685  		goccArgs := []string{"gocc", "-o", main, "-Dasm=__asm__"}
   686  		var args []string
   687  		switch base := filepath.Base(path); base {
   688  		case
   689  			"22_floating_point.c",
   690  			"24_math_library.c":
   691  			goccArgs = append(goccArgs, "-lm")
   692  		case "31_args.c":
   693  			args = []string{"arg1", "arg2", "arg3", "arg4", "arg5"}
   694  		case "46_grep.c":
   695  			if err := copyFile(path, filepath.Join(temp, base)); err != nil {
   696  				return err
   697  			}
   698  			args = []string{`[^* ]*[:a:d: ]+\:\*-/: $`, base}
   699  		}
   700  		if !func() (r bool) {
   701  			defer func() {
   702  				if err := recover(); err != nil {
   703  					if *oStackTrace {
   704  						fmt.Printf("%s\n", stack())
   705  					}
   706  					if *oTrace {
   707  						fmt.Println(err)
   708  					}
   709  					if !oQuiet {
   710  						fail(t, "%s: %v", path, err)
   711  					}
   712  					r = false
   713  				}
   714  			}()
   715  
   716  			goccArgs = append(goccArgs, path)
   717  			if _, err := execute(goccArgs, optimize); err != nil {
   718  				if *oTrace {
   719  					fmt.Println(err)
   720  				}
   721  				if !oQuiet {
   722  					fail(t, "%s: %v", path, err)
   723  				}
   724  				return false
   725  			}
   726  
   727  			return true
   728  		}() {
   729  			return nil
   730  		}
   731  
   732  		out, err := exec.Command("go", append([]string{"run", main}, args...)...).CombinedOutput()
   733  		if err != nil {
   734  			if *oTrace {
   735  				fmt.Println(err)
   736  			}
   737  			t.Errorf("%v: %s\n%v", path, out, err)
   738  			return nil
   739  		}
   740  
   741  		if *oTraceO {
   742  			fmt.Printf("%s\n", out)
   743  		}
   744  		exp, err := ioutil.ReadFile(noExt(path) + ".expect")
   745  		if err != nil {
   746  			if os.IsNotExist(err) {
   747  				fmt.Fprintln(w, filepath.Base(path))
   748  				ok++
   749  				return nil
   750  			}
   751  
   752  			return err
   753  		}
   754  
   755  		out = trim(out)
   756  		exp = trim(exp)
   757  
   758  		switch base := filepath.Base(path); base {
   759  		case "70_floating_point_literals.c": //TODO TCC binary extension
   760  			a := strings.Split(string(exp), "\n")
   761  			exp = []byte(strings.Join(a[:35], "\n"))
   762  		}
   763  
   764  		if !bytes.Equal(out, exp) {
   765  			if *oTrace {
   766  				fmt.Println(err)
   767  			}
   768  			t.Errorf("%v: %s\nout\n%s\nexp\n%s", path, cmp.Diff(string(exp), string(out)), out, exp)
   769  			return nil
   770  		}
   771  
   772  		fmt.Fprintln(w, filepath.Base(path))
   773  		ok++
   774  		return nil
   775  	}); err != nil {
   776  		fail(t, "%v", err)
   777  	}
   778  	return files, ok
   779  }
   780  
   781  func noExt(s string) string {
   782  	ext := filepath.Ext(s)
   783  	if ext == "" {
   784  		panic("internal error") //TODOOK
   785  	}
   786  	return s[:len(s)-len(ext)]
   787  }
   788  
   789  func copyFile(src, dst string) error {
   790  	b, err := ioutil.ReadFile(src)
   791  	if err != nil {
   792  		return err
   793  	}
   794  
   795  	return ioutil.WriteFile(dst, b, 0660)
   796  }
   797  
   798  func trim(b []byte) (r []byte) {
   799  	b = bytes.TrimLeft(b, "\n")
   800  	b = bytes.TrimRight(b, "\n")
   801  	a := bytes.Split(b, []byte("\n"))
   802  	for i, v := range a {
   803  		a[i] = bytes.TrimSpace(v)
   804  	}
   805  	return bytes.Join(a, []byte("\n"))
   806  }
   807  
   808  func execute(args []string, optimize bool, more ...cc.Source) ([]byte, error) {
   809  	args = append(args, "-w")
   810  	if *oM32 {
   811  		args = append(args, "-m32")
   812  	}
   813  	if optimize {
   814  		args = append(args, "-O")
   815  	}
   816  	t, err := newTask(args)
   817  	if err != nil {
   818  		return nil, err
   819  	}
   820  
   821  	t.testSources = more
   822  	t.doNotCache = true
   823  	var stdout, stderr bytes.Buffer
   824  	rc := t.main(&stdout, &stderr)
   825  	if stdout.Len() != 0 {
   826  		fmt.Printf("%s", stdout.Bytes())
   827  	}
   828  	if stderr.Len() != 0 {
   829  		return nil, fmt.Errorf("%s", stderr.Bytes())
   830  	}
   831  
   832  	if rc != 0 {
   833  		return nil, fmt.Errorf("internal error")
   834  	}
   835  
   836  	return stdout.Bytes(), nil
   837  }
   838  
   839  func skipDir(path string) error {
   840  	if strings.HasPrefix(filepath.Base(path), ".") {
   841  		return filepath.SkipDir
   842  	}
   843  
   844  	return nil
   845  }
   846  
   847  func h(v interface{}) string {
   848  	switch x := v.(type) {
   849  	case int:
   850  		return humanize.Comma(int64(x))
   851  	case int64:
   852  		return humanize.Comma(x)
   853  	case uint64:
   854  		return humanize.Comma(int64(x))
   855  	case float64:
   856  		return humanize.CommafWithDigits(x, 0)
   857  	default:
   858  		panic(fmt.Errorf("%T", x)) //TODOOK
   859  	}
   860  }
   861  
   862  func TestMiniGMP(t *testing.T) {
   863  	g := newGolden(t, fmt.Sprintf("testdata/mini-gmp_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
   864  
   865  	defer g.close()
   866  
   867  	var files, ok int
   868  	t.Run("noOpt", func(t *testing.T) {
   869  		files, ok = testMiniGMP(g.w, t, false, nil)
   870  	})
   871  	t.Logf("files %s, ok %s", h(files), h(ok))
   872  
   873  	g2 := newGolden(t, fmt.Sprintf("testdata/mini-gmp_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH))
   874  
   875  	defer g2.close()
   876  
   877  	var blacklist map[string]struct{}
   878  	if arch == 32 || *oM32 {
   879  		blacklist = map[string]struct{}{
   880  			"t-double": {}, // gcc 7.4 -O bug
   881  			"t-cmp_d":  {}, // gcc 7.4 -O bug
   882  		}
   883  	}
   884  	t.Run("opt", func(t *testing.T) {
   885  		files, ok = testMiniGMP(g2.w, t, true, blacklist)
   886  	})
   887  	t.Logf("files %s, ok %s", h(files), h(ok))
   888  }
   889  
   890  func testMiniGMP(w io.Writer, t *testing.T, opt bool, blacklist map[string]struct{}) (files, ok int) {
   891  	var re *regexp.Regexp
   892  	if s := *oRE; s != "" {
   893  		re = regexp.MustCompile(s)
   894  	}
   895  
   896  	b, err := ioutil.ReadFile(filepath.FromSlash("testdata/mini-gmp.tar.gz"))
   897  	if err != nil {
   898  		t.Fatal(err)
   899  	}
   900  
   901  	dir, err := ioutil.TempDir("", "gocc-test-")
   902  	if err != nil {
   903  		t.Fatal(err)
   904  	}
   905  
   906  	defer os.RemoveAll(dir)
   907  
   908  	if err := untar(dir, bytes.NewReader(b)); err != nil {
   909  		t.Fatal(err)
   910  	}
   911  
   912  	wd, err := os.Getwd()
   913  	if err != nil {
   914  		t.Fatal(err)
   915  	}
   916  
   917  	if err := os.Chdir(filepath.Join(dir, filepath.FromSlash("mini-gmp/tests"))); err != nil {
   918  		t.Fatal(err)
   919  	}
   920  
   921  	defer os.Chdir(wd)
   922  
   923  	for _, v := range strings.Split(strings.TrimSpace(`
   924  gocc -w -c testutils.c -o testutils.o
   925  gocc -w -c t-add.c -o t-add.o
   926  gocc -w -c hex-random.c -o hex-random.o
   927  gocc -w -c mini-random.c -o mini-random.o
   928  gocc -w t-add.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-add
   929  gocc -w -c t-sub.c -o t-sub.o
   930  gocc -w t-sub.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-sub
   931  gocc -w -c t-mul.c -o t-mul.o
   932  gocc -w t-mul.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-mul
   933  gocc -w -c t-invert.c -o t-invert.o
   934  gocc -w t-invert.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-invert
   935  gocc -w -c t-div.c -o t-div.o
   936  gocc -w t-div.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-div
   937  gocc -w -c t-div_2exp.c -o t-div_2exp.o
   938  gocc -w t-div_2exp.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-div_2exp
   939  gocc -w -c t-double.c -o t-double.o
   940  gocc -w t-double.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-double
   941  gocc -w -c t-cmp_d.c -o t-cmp_d.o
   942  gocc -w t-cmp_d.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-cmp_d
   943  gocc -w -c t-gcd.c -o t-gcd.o
   944  gocc -w t-gcd.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-gcd
   945  gocc -w -c t-lcm.c -o t-lcm.o
   946  gocc -w t-lcm.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-lcm
   947  gocc -w -c t-import.c -o t-import.o
   948  gocc -w t-import.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-import
   949  gocc -w -c t-comb.c -o t-comb.o
   950  gocc -w t-comb.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-comb
   951  gocc -w -c t-signed.c -o t-signed.o
   952  gocc -w t-signed.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-signed
   953  gocc -w -c t-sqrt.c -o t-sqrt.o
   954  gocc -w t-sqrt.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-sqrt
   955  gocc -w -c t-root.c -o t-root.o
   956  gocc -w t-root.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-root
   957  gocc -w -c t-powm.c -o t-powm.o
   958  gocc -w t-powm.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-powm
   959  gocc -w -c t-logops.c -o t-logops.o
   960  gocc -w t-logops.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-logops
   961  gocc -w -c t-bitops.c -o t-bitops.o
   962  gocc -w t-bitops.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-bitops
   963  gocc -w -c t-scan.c -o t-scan.o
   964  gocc -w t-scan.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-scan
   965  gocc -w -c t-str.c -o t-str.o
   966  gocc -w t-str.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-str
   967  gocc -w -c t-reuse.c -o t-reuse.o
   968  gocc -w t-reuse.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-reuse
   969  gocc -w -c t-aorsmul.c -o t-aorsmul.o
   970  gocc -w t-aorsmul.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-aorsmul
   971  gocc -w -c t-limbs.c -o t-limbs.o
   972  gocc -w t-limbs.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-limbs
   973  gocc -w -c t-cong.c -o t-cong.o
   974  gocc -w t-cong.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-cong
   975  gocc -w -c t-pprime_p.c -o t-pprime_p.o
   976  gocc -w t-pprime_p.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-pprime_p
   977  `), "\n") {
   978  
   979  		if *oTrace {
   980  			fmt.Fprintln(os.Stderr, v)
   981  		}
   982  		out, err := execute(strings.Split(v, " "), opt)
   983  		if err != nil {
   984  			t.Fatalf("%s\n%v", out, err)
   985  		}
   986  	}
   987  	for _, v := range strings.Split("t-add t-sub t-mul t-invert t-div t-div_2exp t-double t-cmp_d t-gcd t-lcm t-import t-comb t-signed t-sqrt t-root t-powm t-logops t-bitops t-scan t-str t-reuse t-aorsmul t-limbs t-cong t-pprime_p", " ") {
   988  		if _, ok := blacklist[v]; ok {
   989  			continue
   990  		}
   991  
   992  		if *oTrace {
   993  			fmt.Fprintln(os.Stderr, v)
   994  		}
   995  		files++
   996  		if re != nil && !re.MatchString(v) {
   997  			continue
   998  		}
   999  
  1000  		out, err := exec.Command("./" + v).CombinedOutput()
  1001  		if err != nil {
  1002  			t.Errorf("%v\n%s\n%v", v, out, err)
  1003  			continue
  1004  		}
  1005  
  1006  		fmt.Fprintln(w, v)
  1007  		ok++
  1008  	}
  1009  	return files, ok
  1010  }
  1011  
  1012  func untar(root string, r io.Reader) error {
  1013  	gr, err := gzip.NewReader(r)
  1014  	if err != nil {
  1015  		return err
  1016  	}
  1017  
  1018  	tr := tar.NewReader(gr)
  1019  	for {
  1020  		hdr, err := tr.Next()
  1021  		if err != nil {
  1022  			if err != io.EOF {
  1023  				return err
  1024  			}
  1025  
  1026  			return nil
  1027  		}
  1028  
  1029  		switch hdr.Typeflag {
  1030  		case tar.TypeDir:
  1031  			if err = os.MkdirAll(filepath.Join(root, hdr.Name), 0770); err != nil {
  1032  				return err
  1033  			}
  1034  		case tar.TypeReg, tar.TypeRegA:
  1035  			f, err := os.OpenFile(filepath.Join(root, hdr.Name), os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode))
  1036  			if err != nil {
  1037  				return err
  1038  			}
  1039  
  1040  			w := bufio.NewWriter(f)
  1041  			if _, err = io.Copy(w, tr); err != nil {
  1042  				return err
  1043  			}
  1044  
  1045  			if err := w.Flush(); err != nil {
  1046  				return err
  1047  			}
  1048  
  1049  			if err := f.Close(); err != nil {
  1050  				return err
  1051  			}
  1052  		default:
  1053  			return fmt.Errorf("unexpected tar header typeflag %#02x", hdr.Typeflag)
  1054  		}
  1055  	}
  1056  }
  1057  
  1058  func dumpTODOs(t *testing.T) {
  1059  	var a []string
  1060  	sum := 0
  1061  	for k, v := range todos {
  1062  		sum += v
  1063  		a = append(a, fmt.Sprintf("%6d %s:%d", v, k.file, k.line))
  1064  	}
  1065  	sort.Sort(sort.Reverse(sort.StringSlice(a)))
  1066  	t.Logf("\n%s\nsum: %d", strings.Join(a, "\n"), sum)
  1067  }
  1068  
  1069  func TestGCCExec(t *testing.T) {
  1070  	root := filepath.Join(testWD, filepath.FromSlash(gccDir))
  1071  	if _, err := os.Stat(root); err != nil {
  1072  		t.Fatalf("Missing resources in %s. Please run 'go test -download -dev' to fix.", root)
  1073  	}
  1074  
  1075  	g := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1076  
  1077  	defer g.close()
  1078  
  1079  	todos = map[todoPos]int{}
  1080  	var files, ok int
  1081  	if *oEdit {
  1082  		defer func() {
  1083  			fmt.Printf("GCC files %s, ok %s\n", h(files), h(ok))
  1084  		}()
  1085  	}
  1086  	const dir = "gcc/testsuite/gcc.c-torture/execute"
  1087  	t.Run("noOpt", func(t *testing.T) {
  1088  		f, o := testGCCExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false)
  1089  		files += f
  1090  		ok += o
  1091  	})
  1092  	t.Logf("files %s, ok %s", h(files), h(ok))
  1093  	if !oQuiet {
  1094  		dumpTODOs(t)
  1095  	}
  1096  
  1097  	g2 := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH))
  1098  
  1099  	defer g2.close()
  1100  	todos = map[todoPos]int{}
  1101  	files = 0
  1102  	ok = 0
  1103  	t.Run("opt", func(t *testing.T) {
  1104  		f, o := testGCCExec(g2.w, t, filepath.Join(root, filepath.FromSlash(dir)), true)
  1105  		files += f
  1106  		ok += o
  1107  	})
  1108  	t.Logf("files %s, ok %s", h(files), h(ok))
  1109  	if !oQuiet {
  1110  		dumpTODOs(t)
  1111  	}
  1112  }
  1113  
  1114  func testGCCExec(w io.Writer, t *testing.T, dir string, opt bool) (files, ok int) {
  1115  	const binaryName = "a.out"
  1116  	blacklist := map[string]struct{}{ //TODO-
  1117  		"20021127-1.c": {}, // non standard GCC behavior
  1118  		"strlen-3.c":   {}, // not a standalone test
  1119  		"eeprof-1.c":   {}, // requires instrumentation
  1120  
  1121  		"20010904-1.c":        {}, //TODO __attribute__((aligned(alignment)))
  1122  		"20010904-2.c":        {}, //TODO __attribute__((aligned(alignment)))
  1123  		"20040411-1.c":        {}, //TODO typedef VLA
  1124  		"20040423-1.c":        {}, //TODO typedef VLA
  1125  		"20041218-2.c":        {}, //TODO struct VLA
  1126  		"20050215-1.c":        {}, //TODO __attribute__ aligned
  1127  		"991014-1.c":          {}, //TODO struct size overflow
  1128  		"align-3.c":           {}, //TODO attr
  1129  		"const-addr-expr-1.c": {}, //TODO complex const addresss initialzer
  1130  		"pr23135.c":           {}, //TODO QBE OOM
  1131  		"pr41935.c":           {}, //TODO * VLA
  1132  		"pr64006.c":           {}, //TODO __builtin_mul_overflow
  1133  		"pr82210.c":           {}, //TODO VLA struct array, hangs
  1134  		"pr85095.c":           {}, //TODO __builtin_add_overflow
  1135  		"rbug.c":              {}, //TODO floating point rounding?
  1136  		"simd-1.c":            {}, //TODO __attribute__((vector_size (16)))
  1137  		"simd-2.c":            {}, //TODO __attribute__((vector_size (16)))
  1138  	}
  1139  	if opt {
  1140  		blacklist["20101011-1.c"] = struct{}{} // gcc 7.4 does not respect __attribute__ ((used)).
  1141  	}
  1142  	if opt && (arch == 32 || *oM32) {
  1143  		blacklist["20030331-1.c"] = struct{}{}    // gcc 7.4 -O -m32 bug
  1144  		blacklist["960830-1.c"] = struct{}{}      // asm
  1145  		blacklist["floatunsisf-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug
  1146  	}
  1147  	wd, err := os.Getwd()
  1148  	if err != nil {
  1149  		t.Fatal(err)
  1150  	}
  1151  
  1152  	defer os.Chdir(wd)
  1153  
  1154  	temp, err := ioutil.TempDir("", "gocc-test-")
  1155  	if err != nil {
  1156  		t.Fatal(err)
  1157  	}
  1158  
  1159  	defer os.RemoveAll(temp)
  1160  
  1161  	if err := os.Chdir(temp); err != nil {
  1162  		t.Fatal(err)
  1163  	}
  1164  
  1165  	var re *regexp.Regexp
  1166  	if s := *oRE; s != "" {
  1167  		re = regexp.MustCompile(s)
  1168  	}
  1169  
  1170  	if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
  1171  		if err != nil {
  1172  			if os.IsNotExist(err) {
  1173  				err = nil
  1174  			}
  1175  			return err
  1176  		}
  1177  
  1178  		if info.IsDir() {
  1179  			return skipDir(path)
  1180  		}
  1181  
  1182  		if strings.Contains(filepath.ToSlash(path), "/builtins/") {
  1183  			return nil
  1184  		}
  1185  
  1186  		if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 {
  1187  			return nil
  1188  		}
  1189  
  1190  		if _, ok := blacklist[filepath.Base(path)]; ok {
  1191  			return nil
  1192  		}
  1193  
  1194  		files++
  1195  
  1196  		if re != nil && !re.MatchString(path) {
  1197  			return nil
  1198  		}
  1199  
  1200  		if *oTrace {
  1201  			fmt.Fprintln(os.Stderr, files, ok, path)
  1202  		}
  1203  
  1204  		if err := os.Remove(binaryName); err != nil && !os.IsNotExist(err) {
  1205  			return err
  1206  		}
  1207  
  1208  		goccArgs := []string{"gocc", "-o", binaryName, "-Dasm=__asm__", "-w"}
  1209  		if !func() (r bool) {
  1210  			defer func() {
  1211  				if err := recover(); err != nil {
  1212  					if *oStackTrace {
  1213  						fmt.Printf("%s\n", stack())
  1214  					}
  1215  					if *oTrace {
  1216  						fmt.Println(err)
  1217  					}
  1218  					if !oQuiet {
  1219  						fail(t, "%s: %v", path, err)
  1220  					}
  1221  					r = false
  1222  				}
  1223  			}()
  1224  
  1225  			if _, err := execute(append(goccArgs, path, "-lm"), opt, gccTestDecls); err != nil {
  1226  				if *oTrace {
  1227  					fmt.Println(err)
  1228  				}
  1229  				if !oQuiet {
  1230  					fail(t, "%s: %v", path, err)
  1231  				}
  1232  				return false
  1233  			}
  1234  
  1235  			return true
  1236  		}() {
  1237  			return nil
  1238  		}
  1239  
  1240  		out, err := exec.Command("./" + binaryName).CombinedOutput()
  1241  		if err != nil {
  1242  			if *oTrace {
  1243  				fmt.Println(err)
  1244  			}
  1245  			t.Errorf("%v: %v: exec fail", path, err)
  1246  			return nil
  1247  		}
  1248  
  1249  		if *oTraceO {
  1250  			fmt.Printf("%s\n", out)
  1251  		}
  1252  
  1253  		fmt.Fprintln(w, filepath.Base(path))
  1254  		ok++
  1255  		return nil
  1256  	}); err != nil {
  1257  		fail(t, "%v", err)
  1258  	}
  1259  	return files, ok
  1260  }
  1261  
  1262  func TestGCCGoExec(t *testing.T) {
  1263  	root := filepath.Join(testWD, filepath.FromSlash(gccDir))
  1264  	if _, err := os.Stat(root); err != nil {
  1265  		t.Fatalf("Missing resources in %s. Please run 'go test -download -dev' to fix.", root)
  1266  	}
  1267  
  1268  	g := newGolden(t, fmt.Sprintf("testdata/gcc_go_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH))
  1269  
  1270  	defer g.close()
  1271  
  1272  	todos = map[todoPos]int{}
  1273  	var files, ok int
  1274  	if *oEdit {
  1275  		defer func() {
  1276  			fmt.Printf("GCC files %s, ok %s\n", h(files), h(ok))
  1277  		}()
  1278  	}
  1279  	const dir = "gcc/testsuite/gcc.c-torture/execute"
  1280  	f, o := testGCCGoExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false)
  1281  	files += f
  1282  	ok += o
  1283  	t.Logf("files %s, ok %s", h(files), h(ok))
  1284  	if !oQuiet {
  1285  		dumpTODOs(t)
  1286  	}
  1287  }
  1288  
  1289  func testGCCGoExec(w io.Writer, t *testing.T, dir string, opt bool) (files, ok int) {
  1290  	const (
  1291  		bin  = "a.out"
  1292  		main = "main.go"
  1293  		crt  = "crt.go"
  1294  	)
  1295  	blacklist := map[string]struct{}{ //TODO-
  1296  		"20021127-1.c": {}, // non standard GCC behavior
  1297  		"strlen-3.c":   {}, // not a standalone test
  1298  		"eeprof-1.c":   {}, // requires instrumentation
  1299  
  1300  		"20010904-1.c":        {}, //TODO __attribute__((aligned(alignment)))
  1301  		"20010904-2.c":        {}, //TODO __attribute__((aligned(alignment)))
  1302  		"20040411-1.c":        {}, //TODO typedef VLA
  1303  		"20040423-1.c":        {}, //TODO typedef VLA
  1304  		"20041218-2.c":        {}, //TODO struct VLA
  1305  		"20050215-1.c":        {}, //TODO __attribute__ aligned
  1306  		"991014-1.c":          {}, //TODO struct size overflow
  1307  		"align-3.c":           {}, //TODO attr
  1308  		"const-addr-expr-1.c": {}, //TODO complex const addresss initialzer
  1309  		"pr23135.c":           {}, //TODO QBE OOM
  1310  		"pr41935.c":           {}, //TODO * VLA
  1311  		"pr64006.c":           {}, //TODO __builtin_mul_overflow
  1312  		"pr82210.c":           {}, //TODO VLA struct array, hangs
  1313  		"pr85095.c":           {}, //TODO __builtin_add_overflow
  1314  		"rbug.c":              {}, //TODO floating point rounding?
  1315  		"simd-1.c":            {}, //TODO __attribute__((vector_size (16)))
  1316  		"simd-2.c":            {}, //TODO __attribute__((vector_size (16)))
  1317  	}
  1318  	if opt {
  1319  		blacklist["20101011-1.c"] = struct{}{} // gcc 7.4 does not respect __attribute__ ((used)).
  1320  	}
  1321  	if opt && (arch == 32 || *oM32) {
  1322  		blacklist["20030331-1.c"] = struct{}{}    // gcc 7.4 -O -m32 bug
  1323  		blacklist["960830-1.c"] = struct{}{}      // asm
  1324  		blacklist["floatunsisf-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug
  1325  	}
  1326  	wd, err := os.Getwd()
  1327  	if err != nil {
  1328  		t.Fatal(err)
  1329  	}
  1330  
  1331  	defer os.Chdir(wd)
  1332  
  1333  	temp, err := ioutil.TempDir("", "gocc-test-")
  1334  	if err != nil {
  1335  		t.Fatal(err)
  1336  	}
  1337  
  1338  	defer os.RemoveAll(temp)
  1339  
  1340  	if err := os.Chdir(temp); err != nil {
  1341  		t.Fatal(err)
  1342  	}
  1343  
  1344  	var re *regexp.Regexp
  1345  	if s := *oRE; s != "" {
  1346  		re = regexp.MustCompile(s)
  1347  	}
  1348  
  1349  	if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
  1350  		if err != nil {
  1351  			if os.IsNotExist(err) {
  1352  				err = nil
  1353  			}
  1354  			return err
  1355  		}
  1356  
  1357  		if info.IsDir() {
  1358  			return skipDir(path)
  1359  		}
  1360  
  1361  		if strings.Contains(filepath.ToSlash(path), "/builtins/") {
  1362  			return nil
  1363  		}
  1364  
  1365  		if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 {
  1366  			return nil
  1367  		}
  1368  
  1369  		if _, ok := blacklist[filepath.Base(path)]; ok {
  1370  			return nil
  1371  		}
  1372  
  1373  		files++
  1374  
  1375  		if re != nil && !re.MatchString(path) {
  1376  			return nil
  1377  		}
  1378  
  1379  		if *oTrace {
  1380  			fmt.Fprintln(os.Stderr, files, ok, path)
  1381  		}
  1382  
  1383  		if err := os.Remove(main); err != nil && !os.IsNotExist(err) {
  1384  			return err
  1385  		}
  1386  
  1387  		goccArgs := []string{
  1388  			"gocc",
  1389  			"-o", main,
  1390  			"-Dasm=__asm__",
  1391  			"-DSIGNAL_SUPPRESS",
  1392  			"-gocc-long-double-is-double",
  1393  			"-gocc-emit-definitions",
  1394  		}
  1395  		if !func() (r bool) {
  1396  			defer func() {
  1397  				if err := recover(); err != nil {
  1398  					if *oStackTrace {
  1399  						fmt.Printf("%s\n", stack())
  1400  					}
  1401  					if *oTrace {
  1402  						fmt.Println(err)
  1403  					}
  1404  					if !oQuiet {
  1405  						fail(t, "%s: %v", path, err)
  1406  					}
  1407  					r = false
  1408  				}
  1409  			}()
  1410  
  1411  			if out, err := execute(append(goccArgs, path), opt, gccTestDecls); err != nil {
  1412  				if *oTrace {
  1413  					fmt.Printf("%s\n%s\n", out, err)
  1414  				}
  1415  				if !oQuiet {
  1416  					fail(t, "%s: %s\n%s", path, out, err)
  1417  				}
  1418  				return false
  1419  			}
  1420  
  1421  			return true
  1422  		}() {
  1423  			return nil
  1424  		}
  1425  
  1426  		os.Remove(bin)
  1427  		out, err := exec.Command("go", "build", "-o", bin, main).CombinedOutput()
  1428  		if err != nil {
  1429  			if *oTrace {
  1430  				fmt.Printf("%s\n%s\n", out, err)
  1431  			}
  1432  			t.Errorf("%v: %s\n%s", path, out, err)
  1433  			return nil
  1434  		}
  1435  
  1436  		if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil {
  1437  			if *oTrace {
  1438  				fmt.Printf("%s\n%s\n", out, err)
  1439  			}
  1440  			t.Errorf("%v: %v: exec fail", path, err)
  1441  			return nil
  1442  		}
  1443  
  1444  		if *oTraceO {
  1445  			fmt.Printf("%s\n", out)
  1446  		}
  1447  
  1448  		fmt.Fprintln(w, filepath.Base(path))
  1449  		ok++
  1450  		return nil
  1451  	}); err != nil {
  1452  		fail(t, "%v", err)
  1453  	}
  1454  	return files, ok
  1455  }
  1456  
  1457  func TestSQLite(t *testing.T) {
  1458  	root := filepath.Join(testWD, filepath.FromSlash(sqliteDir))
  1459  	if _, err := os.Stat(root); err != nil {
  1460  		t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root)
  1461  	}
  1462  
  1463  	t.Run("noOpt", func(t *testing.T) { testSQLite(t, root, false) })
  1464  	t.Run("opt", func(t *testing.T) { testSQLite(t, root, true) })
  1465  }
  1466  
  1467  func testSQLite(t *testing.T, dir string, opt bool) {
  1468  	const binaryName = "a.out"
  1469  	wd, err := os.Getwd()
  1470  	if err != nil {
  1471  		t.Fatal(err)
  1472  	}
  1473  
  1474  	defer os.Chdir(wd)
  1475  
  1476  	temp, err := ioutil.TempDir("", "gocc-test-")
  1477  	if err != nil {
  1478  		t.Fatal(err)
  1479  	}
  1480  
  1481  	defer os.RemoveAll(temp)
  1482  
  1483  	if err := os.Chdir(temp); err != nil {
  1484  		t.Fatal(err)
  1485  	}
  1486  
  1487  	if !func() (r bool) {
  1488  		defer func() {
  1489  			if err := recover(); err != nil {
  1490  				if *oStackTrace {
  1491  					fmt.Printf("%s\n", stack())
  1492  				}
  1493  				if *oTrace {
  1494  					fmt.Println(err)
  1495  				}
  1496  				if !oQuiet {
  1497  					fail(t, "%s: %v", dir, err)
  1498  				}
  1499  				r = false
  1500  			}
  1501  		}()
  1502  
  1503  		if _, err := execute(append([]string{"gocc"}, filepath.Join(dir, "shell.c"), filepath.Join(dir, "sqlite3.c"), "-lpthread", "-ldl"), opt); err != nil {
  1504  			if *oTrace {
  1505  				fmt.Println(err)
  1506  			}
  1507  			if !oQuiet {
  1508  				fail(t, "%s: %v", dir, err)
  1509  			}
  1510  			return false
  1511  		}
  1512  
  1513  		return true
  1514  	}() {
  1515  		return
  1516  	}
  1517  
  1518  	out, err := exec.Command("./"+binaryName, "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput()
  1519  	if err != nil {
  1520  		if *oTrace {
  1521  			fmt.Println(err)
  1522  		}
  1523  		fail(t, "%v", err)
  1524  		return
  1525  	}
  1526  
  1527  	if g, e := strings.TrimSpace(string(out)), "462"; g != e {
  1528  		t.Errorf("%q %q", g, e)
  1529  	}
  1530  	if *oTraceO {
  1531  		fmt.Printf("%s\n", out)
  1532  	}
  1533  
  1534  	if out, err = exec.Command("./"+binaryName, "tmp", "select 13*i from t;").CombinedOutput(); err != nil {
  1535  		if *oTrace {
  1536  			fmt.Println(err)
  1537  		}
  1538  		fail(t, "%v", err)
  1539  		return
  1540  	}
  1541  
  1542  	if g, e := strings.TrimSpace(string(out)), "546"; g != e {
  1543  		t.Errorf("%q %q", g, e)
  1544  	}
  1545  	if *oTraceO {
  1546  		fmt.Printf("%s\n", out)
  1547  	}
  1548  }
  1549  
  1550  func TestSQLiteGo(t *testing.T) {
  1551  	root := filepath.Join(testWD, filepath.FromSlash(sqliteDir))
  1552  	if _, err := os.Stat(root); err != nil {
  1553  		t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root)
  1554  	}
  1555  
  1556  	testSQLiteGo(t, root)
  1557  }
  1558  
  1559  func testSQLiteGo(t *testing.T, dir string) {
  1560  	const main = "main.go"
  1561  	wd, err := os.Getwd()
  1562  	if err != nil {
  1563  		t.Fatal(err)
  1564  	}
  1565  
  1566  	defer os.Chdir(wd)
  1567  
  1568  	temp, err := ioutil.TempDir("", "gocc-test-")
  1569  	if err != nil {
  1570  		t.Fatal(err)
  1571  	}
  1572  
  1573  	defer os.RemoveAll(temp)
  1574  
  1575  	if err := os.Chdir(temp); err != nil {
  1576  		t.Fatal(err)
  1577  	}
  1578  
  1579  	if !func() (r bool) {
  1580  		defer func() {
  1581  			if err := recover(); err != nil {
  1582  				if *oStackTrace {
  1583  					fmt.Printf("%s\n", stack())
  1584  				}
  1585  				if *oTrace {
  1586  					fmt.Println(err)
  1587  				}
  1588  				if !oQuiet {
  1589  					fail(t, "%s: %v", dir, err)
  1590  				}
  1591  				r = false
  1592  			}
  1593  		}()
  1594  
  1595  		if out, err := execute(append([]string{"gocc"},
  1596  			filepath.Join(dir, "shell.c"),
  1597  			"-o", "shell.go",
  1598  			"-DLONGDOUBLE_TYPE=double",
  1599  			"-DSQLITE_DEBUG",
  1600  			"-DSQLITE_DEFAULT_MEMSTATUS=0",
  1601  			"-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1",
  1602  			"-DSQLITE_DQS=0",
  1603  			"-DSQLITE_LIKE_DOESNT_MATCH_BLOBS",
  1604  			"-DSQLITE_MAX_EXPR_DEPTH=0",
  1605  			"-DSQLITE_MEMDEBUG",
  1606  			"-DSQLITE_OMIT_DECLTYPE",
  1607  			"-DSQLITE_OMIT_DEPRECATED",
  1608  			"-DSQLITE_OMIT_PROGRESS_CALLBACK",
  1609  			"-DSQLITE_OMIT_SHARED_CACHE",
  1610  			"-DSQLITE_THREADSAFE=0",
  1611  			"-DSQLITE_USE_ALLOCA",
  1612  		), false); err != nil {
  1613  			if *oTrace {
  1614  				fmt.Printf("%s\n%s\n", out, err)
  1615  			}
  1616  			if !oQuiet {
  1617  				fail(t, "%s: %s\n%s", dir, out, err)
  1618  			}
  1619  			return false
  1620  		}
  1621  
  1622  		if out, err := execute(append([]string{"gocc"},
  1623  			filepath.Join(dir, "sqlite3.c"),
  1624  			"-o", "sqlite3.go",
  1625  			"-qbec-pkgname", "main",
  1626  			"-DLONGDOUBLE_TYPE=double",
  1627  			"-DSQLITE_DEBUG",
  1628  			"-DSQLITE_DEFAULT_MEMSTATUS=0",
  1629  			"-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1",
  1630  			"-DSQLITE_DQS=0",
  1631  			"-DSQLITE_LIKE_DOESNT_MATCH_BLOBS",
  1632  			"-DSQLITE_MAX_EXPR_DEPTH=0",
  1633  			"-DSQLITE_MEMDEBUG",
  1634  			"-DSQLITE_OMIT_DECLTYPE",
  1635  			"-DSQLITE_OMIT_DEPRECATED",
  1636  			"-DSQLITE_OMIT_PROGRESS_CALLBACK",
  1637  			"-DSQLITE_OMIT_SHARED_CACHE",
  1638  			"-DSQLITE_THREADSAFE=0",
  1639  			"-DSQLITE_USE_ALLOCA",
  1640  		),
  1641  			false,
  1642  		); err != nil {
  1643  			if *oTrace {
  1644  				fmt.Printf("%s\n%s\n", out, err)
  1645  			}
  1646  			if !oQuiet {
  1647  				fail(t, "%s: %s\n%s", dir, out, err)
  1648  			}
  1649  			return false
  1650  		}
  1651  
  1652  		return true
  1653  	}() {
  1654  		return
  1655  	}
  1656  
  1657  	// out, err := exec.Command("go", "build", "-tags", "crt.dmesg", "-gcflags", "-e", "-o", "test", "shell.go", "sqlite3.go").CombinedOutput()
  1658  	out, err := exec.Command("go", "build", "-gcflags", "-e", "-o", "test", "shell.go", "sqlite3.go").CombinedOutput()
  1659  	if err != nil {
  1660  		if *oTrace {
  1661  			fmt.Printf("%s\n%s\n", out, err)
  1662  		}
  1663  		fail(t, "%v", err)
  1664  		return
  1665  	}
  1666  
  1667  	if out, err = exec.Command("./test", "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput(); err != nil {
  1668  		if *oTrace {
  1669  			fmt.Printf("%s\n%s\n", out, err)
  1670  		}
  1671  		fail(t, "%v", err)
  1672  		return
  1673  	}
  1674  
  1675  	if g, e := strings.TrimSpace(string(out)), "462"; g != e {
  1676  		t.Errorf("%q %q", g, e)
  1677  	}
  1678  	if *oTraceO {
  1679  		fmt.Printf("%s\n", out)
  1680  	}
  1681  
  1682  	if out, err = exec.Command("./test", "tmp", "select 13*i from t;").CombinedOutput(); err != nil {
  1683  		if *oTrace {
  1684  			fmt.Printf("%s\n%s\n", out, err)
  1685  		}
  1686  		fail(t, "%v", err)
  1687  		return
  1688  	}
  1689  
  1690  	if g, e := strings.TrimSpace(string(out)), "546"; g != e {
  1691  		t.Errorf("%q %q", g, e)
  1692  	}
  1693  	if *oTraceO {
  1694  		fmt.Printf("%s\n", out)
  1695  	}
  1696  }
  1697  
  1698  func fields(t cc.Type) string {
  1699  	var b strings.Builder
  1700  	fields2(t, &b, "")
  1701  	return b.String()
  1702  }
  1703  
  1704  func fields2(t cc.Type, b *strings.Builder, pref string) {
  1705  	fmt.Fprintf(b, "%s==== typ %v, kind %v, sz %v align %v\n", pref, t, t.Kind(), t.Size(), t.Align())
  1706  	for i := 0; i < t.NumField(); i++ {
  1707  		f := t.FieldByIndex([]int{i})
  1708  		fmt.Fprintf(b,
  1709  			"%snm %q, type %v, sz %v, align %v, off %v, pad %v, bitfield %v, boff %v bits %v\n",
  1710  			pref, f.Name(), f.Type(), f.Type().Size(), f.Type().Align(), f.Offset(), f.Padding(),
  1711  			f.IsBitField(), f.BitFieldOffset(), f.BitFieldWidth(),
  1712  		)
  1713  		switch f.Type().Kind() {
  1714  		case cc.Struct, cc.Union:
  1715  			fields2(f.Type(), b, pref+"ยท ")
  1716  		}
  1717  	}
  1718  }
  1719  
  1720  func TestCSmith(t *testing.T) {
  1721  	gcc, err := exec.LookPath("gcc")
  1722  	if err != nil {
  1723  		t.Fatalf("%v", err)
  1724  		return
  1725  	}
  1726  
  1727  	csmith, err := exec.LookPath("csmith")
  1728  	if err != nil {
  1729  		t.Fatalf("%v", err)
  1730  		return
  1731  	}
  1732  
  1733  	if _, err := exec.LookPath("gocc"); err != nil {
  1734  		t.Fatalf("%v: please run go install", err)
  1735  		return
  1736  	}
  1737  
  1738  	binaryName := filepath.FromSlash("./a.out")
  1739  	wd, err := os.Getwd()
  1740  	if err != nil {
  1741  		t.Fatal(err)
  1742  	}
  1743  
  1744  	defer os.Chdir(wd)
  1745  
  1746  	temp, err := ioutil.TempDir("", "gocc-test-")
  1747  	if err != nil {
  1748  		t.Fatal(err)
  1749  	}
  1750  
  1751  	defer os.RemoveAll(temp)
  1752  
  1753  	if err := os.Chdir(temp); err != nil {
  1754  		t.Fatal(err)
  1755  	}
  1756  
  1757  	fixedBugs := []string{
  1758  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1906742816",
  1759  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 612971101",
  1760  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 3629008936",
  1761  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4130344133",
  1762  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3130410542",
  1763  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1833258637",
  1764  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3126091077",
  1765  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324",
  1766  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3043990076",
  1767  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2517344771",
  1768  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 56498550",
  1769  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3645367888",
  1770  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 169375684",
  1771  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3578720023",
  1772  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1885311141",
  1773  	}
  1774  	ch := time.After(*oCSmith)
  1775  	t0 := time.Now()
  1776  	var files, ok int
  1777  	var size int64
  1778  out:
  1779  	for i := 0; ; i++ {
  1780  		extra := ""
  1781  		var args string
  1782  		switch {
  1783  		case i < len(fixedBugs):
  1784  			args += fixedBugs[i]
  1785  			a := strings.Split(fixedBugs[i], " ")
  1786  			extra = strings.Join(a[len(a)-2:], " ")
  1787  			t.Log(args)
  1788  		default:
  1789  			select {
  1790  			case <-ch:
  1791  				break out
  1792  			default:
  1793  			}
  1794  
  1795  			args += csmithDefaultArgs
  1796  		}
  1797  		csOut, err := exec.Command(csmith, strings.Split(args, " ")...).Output()
  1798  		if err != nil {
  1799  			t.Fatalf("%v\n%s", err, csOut)
  1800  		}
  1801  
  1802  		if fn := *oBlackBox; fn != "" {
  1803  			if err := ioutil.WriteFile(fn, csOut, 0660); err != nil {
  1804  				t.Fatal(err)
  1805  			}
  1806  		}
  1807  
  1808  		if err := ioutil.WriteFile("main.c", csOut, 0660); err != nil {
  1809  			t.Fatal(err)
  1810  		}
  1811  
  1812  		csp := fmt.Sprintf("-I%s", filepath.FromSlash("/usr/include/csmith"))
  1813  		ccOut, err := exec.Command(gcc, "-o", binaryName, "main.c", csp).CombinedOutput()
  1814  		if err != nil {
  1815  			t.Fatalf("%s\n%s\ncc: %v", extra, ccOut, err)
  1816  		}
  1817  
  1818  		binOutA, err := func() ([]byte, error) {
  1819  			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  1820  			defer cancel()
  1821  
  1822  			return exec.CommandContext(ctx, binaryName).CombinedOutput()
  1823  		}()
  1824  		if err != nil {
  1825  			continue
  1826  		}
  1827  
  1828  		size += int64(len(csOut))
  1829  
  1830  		if err := os.Remove(binaryName); err != nil {
  1831  			t.Fatal(err)
  1832  		}
  1833  
  1834  		// noOpt
  1835  		files++
  1836  		j, err := newTask([]string{"gocc", "-o", binaryName, "-O0", "-lm", csp, "main.c"})
  1837  		j.doNotCacheMain = true
  1838  		j.Config3.MaxSourceLine = 1 << 19
  1839  		if err != nil {
  1840  			t.Error(err)
  1841  			break
  1842  		}
  1843  
  1844  		func() {
  1845  			var stdout, stderr bytes.Buffer
  1846  
  1847  			defer func() {
  1848  				if err := recover(); err != nil {
  1849  					t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack())
  1850  				}
  1851  			}()
  1852  
  1853  			if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 {
  1854  				t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err)
  1855  			}
  1856  		}()
  1857  
  1858  		binOutB, err := func() ([]byte, error) {
  1859  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  1860  			defer cancel()
  1861  
  1862  			return exec.CommandContext(ctx, binaryName).CombinedOutput()
  1863  		}()
  1864  		if err != nil {
  1865  			t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err)
  1866  			break
  1867  		}
  1868  
  1869  		if g, e := binOutB, binOutA; !bytes.Equal(g, e) {
  1870  			t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e)
  1871  			break
  1872  		}
  1873  
  1874  		ok++
  1875  		if *oTrace {
  1876  			fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " no opt")
  1877  		}
  1878  
  1879  		if err := os.Remove(binaryName); err != nil {
  1880  			t.Fatal(err)
  1881  		}
  1882  
  1883  		// opt
  1884  		files++
  1885  		j, err = newTask([]string{"gocc", "-o", binaryName, "-lm", csp, "main.c"})
  1886  		j.doNotCacheMain = true
  1887  		j.Config3.MaxSourceLine = 1 << 19
  1888  		if err != nil {
  1889  			t.Fatal(err)
  1890  		}
  1891  
  1892  		func() {
  1893  			var stdout, stderr bytes.Buffer
  1894  
  1895  			defer func() {
  1896  				if err := recover(); err != nil {
  1897  					t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack())
  1898  				}
  1899  			}()
  1900  
  1901  			if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 {
  1902  				t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err)
  1903  			}
  1904  		}()
  1905  
  1906  		binOutB, err = func() ([]byte, error) {
  1907  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  1908  			defer cancel()
  1909  
  1910  			return exec.CommandContext(ctx, binaryName).CombinedOutput()
  1911  		}()
  1912  		if err != nil {
  1913  			t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err)
  1914  			break
  1915  		}
  1916  
  1917  		if g, e := binOutB, binOutA; !bytes.Equal(g, e) {
  1918  			t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e)
  1919  			break
  1920  		}
  1921  
  1922  		ok++
  1923  		if *oTrace {
  1924  			fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " opt")
  1925  		}
  1926  
  1927  		// Go
  1928  		os.Remove("main.go")
  1929  		os.Remove(binaryName)
  1930  		files++
  1931  		j, err = newTask([]string{"gocc", "-o", "main.go", csp, "main.c", "-gocc-long-double-is-double"})
  1932  		j.doNotCacheMain = true
  1933  		j.Config3.MaxSourceLine = 1 << 19
  1934  		if err != nil {
  1935  			t.Fatal(err)
  1936  		}
  1937  
  1938  		func() {
  1939  			var stdout, stderr bytes.Buffer
  1940  
  1941  			defer func() {
  1942  				if err := recover(); err != nil {
  1943  					t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack())
  1944  				}
  1945  			}()
  1946  
  1947  			if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 {
  1948  				t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err)
  1949  			}
  1950  		}()
  1951  
  1952  		out, err := exec.Command("go", "build", "-o", binaryName, "main.go").CombinedOutput()
  1953  		if err != nil {
  1954  			t.Errorf("%s\n%s\ngocc: %v", extra, out, err)
  1955  			break
  1956  		}
  1957  
  1958  		binOutB, err = func() ([]byte, error) {
  1959  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  1960  			defer cancel()
  1961  
  1962  			return exec.CommandContext(ctx, binaryName).CombinedOutput()
  1963  		}()
  1964  		if err != nil {
  1965  			t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err)
  1966  			break
  1967  		}
  1968  
  1969  		if g, e := binOutB, binOutA; !bytes.Equal(g, e) {
  1970  			t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e)
  1971  			break
  1972  		}
  1973  
  1974  		ok++
  1975  		if *oTrace {
  1976  			fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " Go")
  1977  		}
  1978  	}
  1979  	d := time.Since(t0)
  1980  	t.Logf("files %v, bytes %v, ok %v in %v", h(files), h(size), h(ok), d)
  1981  }
  1982  
  1983  type compCertResult struct {
  1984  	compiler string
  1985  	test     string
  1986  	run      time.Duration
  1987  	k        float64
  1988  
  1989  	compileOK bool
  1990  	execOK    bool
  1991  	resultOK  bool
  1992  }
  1993  
  1994  func (r *compCertResult) String() string {
  1995  	var s string
  1996  	if r.k != 0 {
  1997  		s = fmt.Sprintf("%8.3f", r.k)
  1998  		if r.k == 1 {
  1999  			s += " *"
  2000  		}
  2001  	}
  2002  	return fmt.Sprintf("%10v%15v%10.3fms%6v%6v%6v%s", r.compiler, r.test, float64(r.run)/float64(time.Millisecond), r.compileOK, r.execOK, r.resultOK, s)
  2003  }
  2004  
  2005  func TestCompCert(t *testing.T) {
  2006  	const root = "testdata/CompCert-3.6/test/c"
  2007  
  2008  	b, err := ioutil.ReadFile(filepath.FromSlash(root + "/Results/knucleotide-input.txt"))
  2009  	if err != nil {
  2010  		t.Fatal(err)
  2011  	}
  2012  
  2013  	dir := filepath.FromSlash(root)
  2014  	m, err := filepath.Glob(filepath.Join(dir, "*.c"))
  2015  	if err != nil {
  2016  		t.Fatal(err)
  2017  	}
  2018  
  2019  	for i, v := range m {
  2020  		v, err := filepath.Abs(v)
  2021  		if err != nil {
  2022  			t.Fatal(err)
  2023  		}
  2024  
  2025  		m[i] = v
  2026  	}
  2027  
  2028  	rdir, err := filepath.Abs(filepath.FromSlash(root + "/Results"))
  2029  	if err != nil {
  2030  		t.Fatal(err)
  2031  	}
  2032  
  2033  	wd, err := os.Getwd()
  2034  	if err != nil {
  2035  		t.Fatal(err)
  2036  	}
  2037  
  2038  	defer os.Chdir(wd)
  2039  
  2040  	temp, err := ioutil.TempDir("", "gocc-test-")
  2041  	if err != nil {
  2042  		t.Fatal(err)
  2043  	}
  2044  
  2045  	defer os.RemoveAll(temp)
  2046  
  2047  	if err := os.Chdir(temp); err != nil {
  2048  		t.Fatal(err)
  2049  	}
  2050  
  2051  	if err := os.Mkdir("Results", 0770); err != nil {
  2052  		t.Fatal(err)
  2053  	}
  2054  
  2055  	if err := ioutil.WriteFile(filepath.FromSlash("Results/knucleotide-input.txt"), b, 0660); err != nil {
  2056  		t.Fatal(err)
  2057  	}
  2058  
  2059  	var r []*compCertResult
  2060  	t.Run("gcc", func(t *testing.T) { r = append(r, testCompCertGcc(t, m, *oCertN, rdir)...) })
  2061  	t.Run("gocc", func(t *testing.T) { r = append(r, testCompCertGocc(t, m, *oCertN, rdir)...) })
  2062  	t.Run("goccgo", func(t *testing.T) { r = append(r, testCompCertGoccgo(t, m, *oCertN, rdir)...) })
  2063  	consider := map[string]struct{}{}
  2064  	for _, v := range r {
  2065  		consider[v.test] = struct{}{}
  2066  	}
  2067  	for _, v := range r {
  2068  		if ok := v.compileOK && v.execOK && v.resultOK; !ok {
  2069  			delete(consider, v.test)
  2070  		}
  2071  	}
  2072  	times := map[string]time.Duration{}
  2073  	tests := map[string][]*compCertResult{}
  2074  	for _, v := range r {
  2075  		if _, ok := consider[v.test]; !ok {
  2076  			continue
  2077  		}
  2078  
  2079  		times[v.compiler] += v.run
  2080  		tests[v.test] = append(tests[v.test], v)
  2081  	}
  2082  	for _, a := range tests {
  2083  		if len(a) < 2 {
  2084  			continue
  2085  		}
  2086  		min := time.Duration(-1)
  2087  		for _, v := range a {
  2088  			if min < 0 || v.run < min {
  2089  				min = v.run
  2090  			}
  2091  		}
  2092  		for _, v := range a {
  2093  			v.k = float64(v.run) / float64(min)
  2094  		}
  2095  	}
  2096  	t.Log("  compiler           test    T         comp  exec match    coef")
  2097  	for _, v := range r {
  2098  		t.Log(v)
  2099  	}
  2100  	var a []string
  2101  	for k := range times {
  2102  		a = append(a, k)
  2103  	}
  2104  	sort.Strings(a)
  2105  	t.Logf("Considered tests: %d/%d", len(consider), len(m))
  2106  	min := time.Duration(-1)
  2107  	for _, v := range times {
  2108  		if min < 0 || v < min {
  2109  			min = v
  2110  		}
  2111  	}
  2112  	for _, k := range a {
  2113  		t.Logf("%10s%15v %6.3f", k, times[k], float64(times[k])/float64(min))
  2114  	}
  2115  }
  2116  
  2117  func testCompCertGcc(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) {
  2118  	const nm = "gcc"
  2119  next:
  2120  	for _, fn := range files {
  2121  		base := filepath.Base(fn)
  2122  		if *oTrace {
  2123  			fmt.Println(base)
  2124  		}
  2125  		bin := nm + "-" + base + ".out"
  2126  		out, err := exec.Command("gcc", "-O", "-o", bin, fn, "-lm").CombinedOutput()
  2127  		if err != nil {
  2128  			t.Errorf("%s: %s:\n%s", base, err, out)
  2129  			r = append(r, &compCertResult{nm, base, 0, 0, false, false, false})
  2130  			continue
  2131  		}
  2132  
  2133  		t0 := time.Now()
  2134  		for i := 0; i < N; i++ {
  2135  			if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil {
  2136  				t.Errorf("%s: %s:\n%s", base, err, out)
  2137  				r = append(r, &compCertResult{nm, base, 0, 0, true, false, false})
  2138  				continue next
  2139  			}
  2140  		}
  2141  		d := time.Since(t0) / time.Duration(N)
  2142  		r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)})
  2143  	}
  2144  	return r
  2145  }
  2146  
  2147  func checkResult(t *testing.T, out []byte, base, rdir string) bool {
  2148  	base = base[:len(base)-len(filepath.Ext(base))]
  2149  	b, err := ioutil.ReadFile(filepath.Join(rdir, base))
  2150  	if err != nil {
  2151  		t.Errorf("%v: %v", base, err)
  2152  		return false
  2153  	}
  2154  
  2155  	if !bytes.Equal(out, b) {
  2156  		t.Logf("got\n%s", hex.Dump(out))
  2157  		t.Logf("exp\n%s", hex.Dump(b))
  2158  		t.Errorf("%v: result differs", base)
  2159  		return false
  2160  	}
  2161  
  2162  	return true
  2163  }
  2164  
  2165  func testCompCertGocc(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) {
  2166  	const nm = "gocc"
  2167  next:
  2168  	for _, fn := range files {
  2169  		base := filepath.Base(fn)
  2170  		if *oTrace {
  2171  			fmt.Println(base)
  2172  		}
  2173  		bin := nm + "-" + base + ".out"
  2174  		out, err := execute([]string{"gocc", "-O", "-o", bin, fn, "-lm"}, false)
  2175  		if err != nil {
  2176  			t.Errorf("%s: %s:\n%s", base, err, out)
  2177  			r = append(r, &compCertResult{nm, base, 0, 0, false, false, false})
  2178  			continue
  2179  		}
  2180  
  2181  		t0 := time.Now()
  2182  		for i := 0; i < N; i++ {
  2183  			if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil {
  2184  				t.Errorf("%s: %s:\n%s", base, err, out)
  2185  				r = append(r, &compCertResult{nm, base, 0, 0, true, false, false})
  2186  				continue next
  2187  			}
  2188  		}
  2189  		d := time.Since(t0) / time.Duration(N)
  2190  		r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)})
  2191  	}
  2192  	return r
  2193  }
  2194  
  2195  func testCompCertGoccgo(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) {
  2196  	const nm = "goccgo"
  2197  next:
  2198  	for _, fn := range files {
  2199  		base := filepath.Base(fn)
  2200  		if *oTrace {
  2201  			fmt.Println(base)
  2202  		}
  2203  		src := nm + "-" + base + ".go"
  2204  		bin := nm + "-" + base + ".out"
  2205  		out, err := execute([]string{"gocc", "-o", src, fn}, false)
  2206  		if err != nil {
  2207  			t.Errorf("%s: %s:\n%s", base, err, out)
  2208  			r = append(r, &compCertResult{nm, base, 0, 0, false, false, false})
  2209  			continue
  2210  		}
  2211  
  2212  		//if out, err = exec.Command("go", "build", "-o", bin, "-tags", "crt.dmesg", src).CombinedOutput(); err != nil {
  2213  		if out, err = exec.Command("go", "build", "-o", bin, src).CombinedOutput(); err != nil {
  2214  			t.Errorf("%s: %s:\n%s", base, err, out)
  2215  			r = append(r, &compCertResult{nm, base, 0, 0, false, false, false})
  2216  			continue next
  2217  		}
  2218  
  2219  		t0 := time.Now()
  2220  		for i := 0; i < N; i++ {
  2221  			if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil {
  2222  				t.Errorf("%s: %s:\n%s", base, err, out)
  2223  				r = append(r, &compCertResult{nm, base, 0, 0, true, false, false})
  2224  				continue next
  2225  			}
  2226  		}
  2227  		d := time.Since(t0) / time.Duration(N)
  2228  		r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)})
  2229  	}
  2230  	return r
  2231  }
  2232  
  2233  func dumpLayout(t cc.Type) string {
  2234  	switch t.Kind() {
  2235  	case cc.Struct, cc.Union:
  2236  		// ok
  2237  	default:
  2238  		return t.String()
  2239  	}
  2240  
  2241  	nf := t.NumField()
  2242  	var a []string
  2243  	for i := 0; i < nf; i++ {
  2244  		f := t.FieldByIndex([]int{i})
  2245  		a = append(a, fmt.Sprintf("%2d: %q: BitFieldOffset %v, BitFieldWidth %v, IsBitField %v, Mask: %#0x, off: %v, pad %v",
  2246  			i, f.Name(), f.BitFieldOffset(), f.BitFieldWidth(),
  2247  			f.IsBitField(), f.Mask(), f.Offset(), f.Padding(),
  2248  		))
  2249  	}
  2250  	return strings.Join(a, "\n")
  2251  }