Source file src/cmd/compile/internal/types2/sizes_test.go

     1  // Copyright 2016 The Go 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  // This file contains tests for sizes.
     6  
     7  package types2_test
     8  
     9  import (
    10  	"cmd/compile/internal/syntax"
    11  	"cmd/compile/internal/types2"
    12  	"internal/testenv"
    13  	"testing"
    14  )
    15  
    16  // findStructType typechecks src and returns the first struct type encountered.
    17  func findStructType(t *testing.T, src string) *types2.Struct {
    18  	return findStructTypeConfig(t, src, &types2.Config{})
    19  }
    20  
    21  func findStructTypeConfig(t *testing.T, src string, conf *types2.Config) *types2.Struct {
    22  	types := make(map[syntax.Expr]types2.TypeAndValue)
    23  	mustTypecheck(src, nil, &types2.Info{Types: types})
    24  	for _, tv := range types {
    25  		if ts, ok := tv.Type.(*types2.Struct); ok {
    26  			return ts
    27  		}
    28  	}
    29  	t.Fatalf("failed to find a struct type in src:\n%s\n", src)
    30  	return nil
    31  }
    32  
    33  // go.dev/issue/16316
    34  func TestMultipleSizeUse(t *testing.T) {
    35  	const src = `
    36  package main
    37  
    38  type S struct {
    39      i int
    40      b bool
    41      s string
    42      n int
    43  }
    44  `
    45  	ts := findStructType(t, src)
    46  	sizes := types2.StdSizes{WordSize: 4, MaxAlign: 4}
    47  	if got := sizes.Sizeof(ts); got != 20 {
    48  		t.Errorf("Sizeof(%v) with WordSize 4 = %d want 20", ts, got)
    49  	}
    50  	sizes = types2.StdSizes{WordSize: 8, MaxAlign: 8}
    51  	if got := sizes.Sizeof(ts); got != 40 {
    52  		t.Errorf("Sizeof(%v) with WordSize 8 = %d want 40", ts, got)
    53  	}
    54  }
    55  
    56  // go.dev/issue/16464
    57  func TestAlignofNaclSlice(t *testing.T) {
    58  	const src = `
    59  package main
    60  
    61  var s struct {
    62  	x *int
    63  	y []byte
    64  }
    65  `
    66  	ts := findStructType(t, src)
    67  	sizes := &types2.StdSizes{WordSize: 4, MaxAlign: 8}
    68  	var fields []*types2.Var
    69  	// Make a copy manually :(
    70  	for i := 0; i < ts.NumFields(); i++ {
    71  		fields = append(fields, ts.Field(i))
    72  	}
    73  	offsets := sizes.Offsetsof(fields)
    74  	if offsets[0] != 0 || offsets[1] != 4 {
    75  		t.Errorf("OffsetsOf(%v) = %v want %v", ts, offsets, []int{0, 4})
    76  	}
    77  }
    78  
    79  func TestIssue16902(t *testing.T) {
    80  	const src = `
    81  package a
    82  
    83  import "unsafe"
    84  
    85  const _ = unsafe.Offsetof(struct{ x int64 }{}.x)
    86  `
    87  	info := types2.Info{Types: make(map[syntax.Expr]types2.TypeAndValue)}
    88  	conf := types2.Config{
    89  		Importer: defaultImporter(),
    90  		Sizes:    &types2.StdSizes{WordSize: 8, MaxAlign: 8},
    91  	}
    92  	mustTypecheck(src, &conf, &info)
    93  	for _, tv := range info.Types {
    94  		_ = conf.Sizes.Sizeof(tv.Type)
    95  		_ = conf.Sizes.Alignof(tv.Type)
    96  	}
    97  }
    98  
    99  // go.dev/issue/53884.
   100  func TestAtomicAlign(t *testing.T) {
   101  	testenv.MustHaveGoBuild(t) // The Go command is needed for the importer to determine the locations of stdlib .a files.
   102  
   103  	const src = `
   104  package main
   105  
   106  import "sync/atomic"
   107  
   108  var s struct {
   109  	x int32
   110  	y atomic.Int64
   111  	z int64
   112  }
   113  `
   114  
   115  	want := []int64{0, 8, 16}
   116  	for _, arch := range []string{"386", "amd64"} {
   117  		t.Run(arch, func(t *testing.T) {
   118  			conf := types2.Config{
   119  				Importer: defaultImporter(),
   120  				Sizes:    types2.SizesFor("gc", arch),
   121  			}
   122  			ts := findStructTypeConfig(t, src, &conf)
   123  			var fields []*types2.Var
   124  			// Make a copy manually :(
   125  			for i := 0; i < ts.NumFields(); i++ {
   126  				fields = append(fields, ts.Field(i))
   127  			}
   128  
   129  			offsets := conf.Sizes.Offsetsof(fields)
   130  			if offsets[0] != want[0] || offsets[1] != want[1] || offsets[2] != want[2] {
   131  				t.Errorf("OffsetsOf(%v) = %v want %v", ts, offsets, want)
   132  			}
   133  		})
   134  	}
   135  }
   136  
   137  type gcSizeTest struct {
   138  	name string
   139  	src  string
   140  }
   141  
   142  var gcSizesTests = []gcSizeTest{
   143  	{
   144  		"issue60431",
   145  		`
   146  package main
   147  
   148  import "unsafe"
   149  
   150  // The foo struct size is expected to be rounded up to 16 bytes.
   151  type foo struct {
   152  	a int64
   153  	b bool
   154  }
   155  
   156  func main() {
   157  	assert(unsafe.Sizeof(foo{}) == 16)
   158  }`,
   159  	},
   160  	{
   161  		"issue60734",
   162  		`
   163  package main
   164  
   165  import (
   166  	"unsafe"
   167  )
   168  
   169  // The Data struct size is expected to be rounded up to 16 bytes.
   170  type Data struct {
   171  	Value  uint32   // 4 bytes
   172  	Label  [10]byte // 10 bytes
   173  	Active bool     // 1 byte
   174  	// padded with 1 byte to make it align
   175  }
   176  
   177  func main() {
   178  	assert(unsafe.Sizeof(Data{}) == 16)
   179  }
   180  `,
   181  	},
   182  }
   183  
   184  func TestGCSizes(t *testing.T) {
   185  	types2.DefPredeclaredTestFuncs()
   186  	for _, tc := range gcSizesTests {
   187  		tc := tc
   188  		t.Run(tc.name, func(t *testing.T) {
   189  			t.Parallel()
   190  			conf := types2.Config{Importer: defaultImporter(), Sizes: types2.SizesFor("gc", "amd64")}
   191  			mustTypecheck(tc.src, &conf, nil)
   192  		})
   193  	}
   194  }
   195  

View as plain text