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

View as plain text