cgo.go raw

   1  // Package cgo implements CGo by modifying a loaded AST. It does this by parsing
   2  // the `import "C"` statements found in the source code with libclang and
   3  // generating stub function and global declarations.
   4  //
   5  // There are a few advantages to modifying the AST directly instead of doing CGo
   6  // as a preprocessing step, with the main advantage being that debug information
   7  // is kept intact as much as possible.
   8  package cgo
   9  
  10  // This file extracts the `import "C"` statement from the source and modifies
  11  // the AST for CGo. It does not use libclang directly: see libclang.go for the C
  12  // source file parsing.
  13  
  14  import (
  15  	"fmt"
  16  	"go/ast"
  17  	"go/parser"
  18  	"go/scanner"
  19  	"go/token"
  20  	"path/filepath"
  21  	"sort"
  22  	"strconv"
  23  	"strings"
  24  
  25  	"github.com/google/shlex"
  26  	"golang.org/x/tools/go/ast/astutil"
  27  )
  28  
  29  // Function that's only defined in Go 1.22.
  30  var setASTFileFields = func(f *ast.File, start, end token.Pos) {
  31  }
  32  
  33  // cgoPackage holds all CGo-related information of a package.
  34  type cgoPackage struct {
  35  	generated       *ast.File
  36  	packageName     string
  37  	cgoFiles        []*ast.File
  38  	generatedPos    token.Pos
  39  	errors          []error
  40  	currentDir      string // current working directory
  41  	packageDir      string // full path to the package to process
  42  	importPath      string
  43  	fset            *token.FileSet
  44  	tokenFiles      map[string]*token.File
  45  	definedGlobally map[string]ast.Node
  46  	noescapingFuncs map[string]*noescapingFunc // #cgo noescape lines
  47  	anonDecls       map[interface{}]string
  48  	cflags          []string // CFlags from #cgo lines
  49  	ldflags         []string // LDFlags from #cgo lines
  50  	visitedFiles    map[string][]byte
  51  	cgoHeaders      []string
  52  }
  53  
  54  // cgoFile holds information only for a single Go file (with one or more
  55  // `import "C"` statements).
  56  type cgoFile struct {
  57  	*cgoPackage
  58  	file    *ast.File
  59  	index   int
  60  	defined map[string]ast.Node
  61  	names   map[string]clangCursor
  62  }
  63  
  64  // elaboratedTypeInfo contains some information about an elaborated type
  65  // (struct, union) found in the C AST.
  66  type elaboratedTypeInfo struct {
  67  	typeExpr   *ast.StructType
  68  	pos        token.Pos
  69  	bitfields  []bitfieldInfo
  70  	unionSize  int64 // union size in bytes, nonzero when union getters/setters should be created
  71  	unionAlign int64 // union alignment in bytes
  72  }
  73  
  74  // bitfieldInfo contains information about a single bitfield in a struct. It
  75  // keeps information about the start, end, and the special (renamed) base field
  76  // of this bitfield.
  77  type bitfieldInfo struct {
  78  	field    *ast.Field
  79  	name     string
  80  	pos      token.Pos
  81  	startBit int64
  82  	endBit   int64 // may be 0 meaning "until the end of the field"
  83  }
  84  
  85  // Information about a #cgo noescape line in the source code.
  86  type noescapingFunc struct {
  87  	name string
  88  	pos  token.Pos
  89  	used bool // true if used somewhere in the source (for proper error reporting)
  90  }
  91  
  92  // cgoAliases list type aliases between Go and C, for types that are equivalent
  93  // in both languages. See addTypeAliases.
  94  var cgoAliases = map[string]string{
  95  	"_Cgo_int8_t":    "int8",
  96  	"_Cgo_int16_t":   "int16",
  97  	"_Cgo_int32_t":   "int32",
  98  	"_Cgo_int64_t":   "int64",
  99  	"_Cgo_uint8_t":   "uint8",
 100  	"_Cgo_uint16_t":  "uint16",
 101  	"_Cgo_uint32_t":  "uint32",
 102  	"_Cgo_uint64_t":  "uint64",
 103  	"_Cgo_uintptr_t": "uintptr",
 104  	"_Cgo_float":     "float32",
 105  	"_Cgo_double":    "float64",
 106  	"_Cgo__Bool":     "bool",
 107  }
 108  
 109  // builtinAliases are handled specially because they only exist on the Go side
 110  // of CGo, not on the CGo side (they're prefixed with "_Cgo_" there).
 111  var builtinAliases = []string{
 112  	"char",
 113  	"schar",
 114  	"uchar",
 115  	"short",
 116  	"ushort",
 117  	"int",
 118  	"uint",
 119  	"long",
 120  	"ulong",
 121  	"longlong",
 122  	"ulonglong",
 123  }
 124  
 125  // builtinAliasTypedefs lists some C types with ambiguous sizes that must be
 126  // retrieved somehow from C. This is done by adding some typedefs to get the
 127  // size of each type.
 128  const builtinAliasTypedefs = `
 129  # 1 "<cgo>"
 130  typedef char                _Cgo_char;
 131  typedef signed char         _Cgo_schar;
 132  typedef unsigned char       _Cgo_uchar;
 133  typedef short               _Cgo_short;
 134  typedef unsigned short      _Cgo_ushort;
 135  typedef int                 _Cgo_int;
 136  typedef unsigned int        _Cgo_uint;
 137  typedef long                _Cgo_long;
 138  typedef unsigned long       _Cgo_ulong;
 139  typedef long long           _Cgo_longlong;
 140  typedef unsigned long long  _Cgo_ulonglong;
 141  `
 142  
 143  // First part of the generated Go file. Written here as Go because that's much
 144  // easier than constructing the entire AST in memory.
 145  // The string/bytes functions below implement C.CString etc. To make sure the
 146  // runtime doesn't need to know the C int type, lengths are converted to uintptr
 147  // first.
 148  const generatedGoFilePrefixBase = `
 149  import "syscall"
 150  import "unsafe"
 151  
 152  var _ unsafe.Pointer
 153  
 154  //go:linkname _Cgo_CString runtime.cgo_CString
 155  func _Cgo_CString(string) *_Cgo_char
 156  
 157  //go:linkname _Cgo_GoString runtime.cgo_GoString
 158  func _Cgo_GoString(*_Cgo_char) string
 159  
 160  //go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
 161  func _Cgo___GoStringN(*_Cgo_char, uintptr) string
 162  
 163  func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
 164  	return _Cgo___GoStringN(cstr, uintptr(length))
 165  }
 166  
 167  //go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
 168  func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
 169  
 170  func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
 171  	return _Cgo___GoBytes(ptr, uintptr(length))
 172  }
 173  
 174  //go:linkname _Cgo___CBytes runtime.cgo_CBytes
 175  func _Cgo___CBytes([]byte) unsafe.Pointer
 176  
 177  func _Cgo_CBytes(b []byte) unsafe.Pointer {
 178  	return _Cgo___CBytes(b)
 179  }
 180  
 181  //go:linkname _Cgo___get_errno_num runtime.cgo_errno
 182  func _Cgo___get_errno_num() uintptr
 183  `
 184  
 185  const generatedGoFilePrefixOther = generatedGoFilePrefixBase + `
 186  func _Cgo___get_errno() error {
 187  	return syscall.Errno(_Cgo___get_errno_num())
 188  }
 189  `
 190  
 191  // Windows uses fake errno values in the syscall package.
 192  // See for example: https://github.com/golang/go/issues/23468
 193  // Moxie uses mingw-w64 though, which does have defined errno values. Since the
 194  // syscall package is the standard library one we can't change it, but we can
 195  // map the errno values to match the values in the syscall package.
 196  // Source of the errno values: lib/mingw-w64/mingw-w64-headers/crt/errno.h
 197  const generatedGoFilePrefixWindows = generatedGoFilePrefixBase + `
 198  var _Cgo___errno_mapping = [...]syscall.Errno{
 199  	1:  syscall.EPERM,
 200  	2:  syscall.ENOENT,
 201  	3:  syscall.ESRCH,
 202  	4:  syscall.EINTR,
 203  	5:  syscall.EIO,
 204  	6:  syscall.ENXIO,
 205  	7:  syscall.E2BIG,
 206  	8:  syscall.ENOEXEC,
 207  	9:  syscall.EBADF,
 208  	10: syscall.ECHILD,
 209  	11: syscall.EAGAIN,
 210  	12: syscall.ENOMEM,
 211  	13: syscall.EACCES,
 212  	14: syscall.EFAULT,
 213  	16: syscall.EBUSY,
 214  	17: syscall.EEXIST,
 215  	18: syscall.EXDEV,
 216  	19: syscall.ENODEV,
 217  	20: syscall.ENOTDIR,
 218  	21: syscall.EISDIR,
 219  	22: syscall.EINVAL,
 220  	23: syscall.ENFILE,
 221  	24: syscall.EMFILE,
 222  	25: syscall.ENOTTY,
 223  	27: syscall.EFBIG,
 224  	28: syscall.ENOSPC,
 225  	29: syscall.ESPIPE,
 226  	30: syscall.EROFS,
 227  	31: syscall.EMLINK,
 228  	32: syscall.EPIPE,
 229  	33: syscall.EDOM,
 230  	34: syscall.ERANGE,
 231  	36: syscall.EDEADLK,
 232  	38: syscall.ENAMETOOLONG,
 233  	39: syscall.ENOLCK,
 234  	40: syscall.ENOSYS,
 235  	41: syscall.ENOTEMPTY,
 236  	42: syscall.EILSEQ,
 237  }
 238  
 239  func _Cgo___get_errno() error {
 240  	num := _Cgo___get_errno_num()
 241  	if num < uintptr(len(_Cgo___errno_mapping)) {
 242  		if mapped := _Cgo___errno_mapping[num]; mapped != 0 {
 243  			return mapped
 244  		}
 245  	}
 246  	return syscall.Errno(num)
 247  }
 248  `
 249  
 250  // Process extracts `import "C"` statements from the AST, parses the comment
 251  // with libclang, and modifies the AST to use this information. It returns a
 252  // newly created *ast.File that should be added to the list of to-be-parsed
 253  // files, the CGo header snippets that should be compiled (for inline
 254  // functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
 255  // hashes of the accessed C header files. If there is one or more error, it
 256  // returns these in the []error slice but still modifies the AST.
 257  func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, goos string) ([]*ast.File, []string, []string, []string, map[string][]byte, []error) {
 258  	p := &cgoPackage{
 259  		packageName:     files[0].Name.Name,
 260  		currentDir:      dir,
 261  		importPath:      importPath,
 262  		fset:            fset,
 263  		tokenFiles:      map[string]*token.File{},
 264  		definedGlobally: map[string]ast.Node{},
 265  		noescapingFuncs: map[string]*noescapingFunc{},
 266  		anonDecls:       map[interface{}]string{},
 267  		visitedFiles:    map[string][]byte{},
 268  	}
 269  
 270  	// Add a new location for the following file.
 271  	generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0)
 272  	generatedTokenPos.SetLines([]int{0})
 273  	p.generatedPos = generatedTokenPos.Pos(0)
 274  
 275  	// Find the absolute path for this package.
 276  	packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
 277  	if err != nil {
 278  		return nil, nil, nil, nil, nil, []error{
 279  			scanner.Error{
 280  				Pos: fset.Position(files[0].Pos()),
 281  				Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
 282  			},
 283  		}
 284  	}
 285  	p.packageDir = filepath.Dir(packagePath)
 286  
 287  	// Construct a new in-memory AST for CGo declarations of this package.
 288  	// The first part is written as Go code that is then parsed, but more code
 289  	// is added later to the AST to declare functions, globals, etc.
 290  	goCode := "package " + files[0].Name.Name + "\n\n"
 291  	if goos == "windows" {
 292  		goCode += generatedGoFilePrefixWindows
 293  	} else {
 294  		goCode += generatedGoFilePrefixOther
 295  	}
 296  	p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments)
 297  	if err != nil {
 298  		// This is always a bug in the cgo package.
 299  		panic("unexpected error: " + err.Error())
 300  	}
 301  	p.cgoFiles = append(p.cgoFiles, p.generated)
 302  	// If the Comments field is not set to nil, the go/format package will get
 303  	// confused about where comments should go.
 304  	p.generated.Comments = nil
 305  
 306  	// Find `import "C"` C fragments in the file.
 307  	p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
 308  	for i, f := range files {
 309  		var cgoHeader string
 310  		for i := 0; i < len(f.Decls); i++ {
 311  			decl := f.Decls[i]
 312  			genDecl, ok := decl.(*ast.GenDecl)
 313  			if !ok {
 314  				continue
 315  			}
 316  			if len(genDecl.Specs) != 1 {
 317  				continue
 318  			}
 319  			spec, ok := genDecl.Specs[0].(*ast.ImportSpec)
 320  			if !ok {
 321  				continue
 322  			}
 323  			path, err := strconv.Unquote(spec.Path.Value)
 324  			if err != nil {
 325  				// This should not happen. An import path that is not properly
 326  				// quoted should not exist in a correct AST.
 327  				panic("could not parse import path: " + err.Error())
 328  			}
 329  			if path != "C" {
 330  				continue
 331  			}
 332  
 333  			// Remove this import declaration.
 334  			f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
 335  			i--
 336  
 337  			if genDecl.Doc == nil {
 338  				continue
 339  			}
 340  
 341  			// Iterate through all parts of the CGo header. Note that every //
 342  			// line is a new comment.
 343  			position := fset.Position(genDecl.Doc.Pos())
 344  			fragment := fmt.Sprintf("# %d %#v\n", position.Line, position.Filename)
 345  			for _, comment := range genDecl.Doc.List {
 346  				// Find all #cgo lines, extract and use their contents, and
 347  				// replace the lines with spaces (to preserve locations).
 348  				c := p.parseCGoPreprocessorLines(comment.Text, comment.Slash)
 349  
 350  				// Change the comment (which is still in Go syntax, with // and
 351  				// /* */ ) to a regular string by replacing the start/end
 352  				// markers of comments with spaces.
 353  				// It is similar to the Text() method but differs in that it
 354  				// doesn't strip anything and tries to keep all offsets correct
 355  				// by adding spaces and newlines where necessary.
 356  				if c[1] == '/' { /* comment */
 357  					c = "  " + c[2:]
 358  				} else { // comment
 359  					c = "  " + c[2:len(c)-2]
 360  				}
 361  				fragment += c + "\n"
 362  			}
 363  			cgoHeader += fragment
 364  		}
 365  
 366  		p.cgoHeaders[i] = cgoHeader
 367  	}
 368  
 369  	// Define CFlags that will be used while parsing the package.
 370  	// Disable _FORTIFY_SOURCE as it causes problems on macOS.
 371  	// Note that it is only disabled for memcpy (etc) calls made from Go, which
 372  	// have better alternatives anyway.
 373  	cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
 374  	cflagsForCGo = append(cflagsForCGo, p.cflags...)
 375  
 376  	// Retrieve types such as C.int, C.longlong, etc from C.
 377  	p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
 378  		gen := &ast.GenDecl{
 379  			TokPos: token.NoPos,
 380  			Tok:    token.TYPE,
 381  		}
 382  		for _, name := range builtinAliases {
 383  			typeSpec := p.getIntegerType("_Cgo_"+name, names["_Cgo_"+name])
 384  			gen.Specs = append(gen.Specs, typeSpec)
 385  		}
 386  		p.generated.Decls = append(p.generated.Decls, gen)
 387  	})
 388  
 389  	// Process CGo imports for each file.
 390  	for i, f := range files {
 391  		cf := p.newCGoFile(f, i)
 392  		// These types are aliased with the corresponding types in C. For
 393  		// example, float in C is always float32 in Go.
 394  		cf.names["float"] = clangCursor{}
 395  		cf.names["double"] = clangCursor{}
 396  		cf.names["_Bool"] = clangCursor{}
 397  		// Now read all the names (identifies) that C defines in the header
 398  		// snippet.
 399  		cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
 400  			for _, name := range builtinAliases {
 401  				// Names such as C.int should not be obtained from C.
 402  				// This works around an issue in picolibc that has `#define int`
 403  				// in a header file.
 404  				delete(names, name)
 405  			}
 406  			astutil.Apply(f, func(cursor *astutil.Cursor) bool {
 407  				return cf.walker(cursor, names)
 408  			}, nil)
 409  		})
 410  	}
 411  
 412  	// Show an error when a #cgo noescape line isn't used in practice.
 413  	// This matches upstream Go. I think the goal is to avoid issues with
 414  	// misspelled function names, which seems very useful.
 415  	var unusedNoescapeLines []*noescapingFunc
 416  	for _, value := range p.noescapingFuncs {
 417  		if !value.used {
 418  			unusedNoescapeLines = append(unusedNoescapeLines, value)
 419  		}
 420  	}
 421  	sort.SliceStable(unusedNoescapeLines, func(i, j int) bool {
 422  		return unusedNoescapeLines[i].pos < unusedNoescapeLines[j].pos
 423  	})
 424  	for _, value := range unusedNoescapeLines {
 425  		p.addError(value.pos, fmt.Sprintf("function %#v in #cgo noescape line is not used", value.name))
 426  	}
 427  
 428  	// Print the newly generated in-memory AST, for debugging.
 429  	//ast.Print(fset, p.generated)
 430  
 431  	return p.cgoFiles, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
 432  }
 433  
 434  func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
 435  	return &cgoFile{
 436  		cgoPackage: p,
 437  		file:       file,
 438  		index:      index,
 439  		defined:    make(map[string]ast.Node),
 440  		names:      make(map[string]clangCursor),
 441  	}
 442  }
 443  
 444  // makePathsAbsolute converts some common path compiler flags (-I, -L) from
 445  // relative flags into absolute flags, if they are relative. This is necessary
 446  // because the C compiler is usually not invoked from the package path.
 447  func (p *cgoPackage) makePathsAbsolute(args []string) {
 448  	nextIsPath := false
 449  	for i, arg := range args {
 450  		if nextIsPath {
 451  			if !filepath.IsAbs(arg) {
 452  				args[i] = filepath.Join(p.packageDir, arg)
 453  			}
 454  		}
 455  		if arg == "-I" || arg == "-L" {
 456  			nextIsPath = true
 457  			continue
 458  		}
 459  		if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
 460  			path := arg[2:]
 461  			if !filepath.IsAbs(path) {
 462  				args[i] = arg[:2] + filepath.Join(p.packageDir, path)
 463  			}
 464  		}
 465  	}
 466  }
 467  
 468  // parseCGoPreprocessorLines reads #cgo pseudo-preprocessor lines in the source
 469  // text (import "C" fragment), stores their information such as CFLAGS, and
 470  // returns the same text but with those #cgo lines replaced by spaces (to keep
 471  // position offsets the same).
 472  func (p *cgoPackage) parseCGoPreprocessorLines(text string, pos token.Pos) string {
 473  	for {
 474  		// Extract the #cgo line, and replace it with spaces.
 475  		// Replacing with spaces makes sure that error locations are
 476  		// still correct, while not interfering with parsing in any way.
 477  		lineStart := strings.Index(text, "#cgo ")
 478  		if lineStart < 0 {
 479  			break
 480  		}
 481  		lineLen := strings.IndexByte(text[lineStart:], '\n')
 482  		if lineLen < 0 {
 483  			lineLen = len(text) - lineStart
 484  		}
 485  		lineEnd := lineStart + lineLen
 486  		line := text[lineStart:lineEnd]
 487  		spaces := make([]byte, len(line))
 488  		for i := range spaces {
 489  			spaces[i] = ' '
 490  		}
 491  		text = text[:lineStart] + string(spaces) + text[lineEnd:]
 492  
 493  		allFields := strings.Fields(line[4:])
 494  		switch allFields[0] {
 495  		case "noescape":
 496  			// The code indicates that pointer parameters will not be captured
 497  			// by the called C function.
 498  			if len(allFields) < 2 {
 499  				p.addErrorAfter(pos, text[:lineStart], "missing function name in #cgo noescape line")
 500  				continue
 501  			}
 502  			if len(allFields) > 2 {
 503  				p.addErrorAfter(pos, text[:lineStart], "multiple function names in #cgo noescape line")
 504  				continue
 505  			}
 506  			name := allFields[1]
 507  			p.noescapingFuncs[name] = &noescapingFunc{
 508  				name: name,
 509  				pos:  pos,
 510  				used: false,
 511  			}
 512  			continue
 513  		case "nocallback":
 514  			// We don't do anything special when calling a C function, so there
 515  			// appears to be no optimization that we can do here.
 516  			// Accept, but ignore the parameter for compatibility.
 517  			continue
 518  		}
 519  
 520  		// Get the text before the colon in the #cgo directive.
 521  		colon := strings.IndexByte(line, ':')
 522  		if colon < 0 {
 523  			p.addErrorAfter(pos, text[:lineStart], "missing colon in #cgo line")
 524  			continue
 525  		}
 526  
 527  		// Extract the fields before the colon. These fields are a list
 528  		// of build tags and the C environment variable.
 529  		fields := strings.Fields(line[4:colon])
 530  		if len(fields) == 0 {
 531  			p.addErrorAfter(pos, text[:lineStart+colon-1], "invalid #cgo line")
 532  			continue
 533  		}
 534  
 535  		if len(fields) > 1 {
 536  			p.addErrorAfter(pos, text[:lineStart+5], "not implemented: build constraints in #cgo line")
 537  			continue
 538  		}
 539  
 540  		name := fields[len(fields)-1]
 541  		value := line[colon+1:]
 542  		switch name {
 543  		case "CFLAGS":
 544  			flags, err := shlex.Split(value)
 545  			if err != nil {
 546  				// TODO: find the exact location where the error happened.
 547  				p.addErrorAfter(pos, text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
 548  				continue
 549  			}
 550  			if err := checkCompilerFlags(name, flags); err != nil {
 551  				p.addErrorAfter(pos, text[:lineStart+colon+1], err.Error())
 552  				continue
 553  			}
 554  			p.makePathsAbsolute(flags)
 555  			p.cflags = append(p.cflags, flags...)
 556  		case "LDFLAGS":
 557  			flags, err := shlex.Split(value)
 558  			if err != nil {
 559  				// TODO: find the exact location where the error happened.
 560  				p.addErrorAfter(pos, text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
 561  				continue
 562  			}
 563  			if err := checkLinkerFlags(name, flags); err != nil {
 564  				p.addErrorAfter(pos, text[:lineStart+colon+1], err.Error())
 565  				continue
 566  			}
 567  			p.makePathsAbsolute(flags)
 568  			p.ldflags = append(p.ldflags, flags...)
 569  		default:
 570  			startPos := strings.LastIndex(line[4:colon], name) + 4
 571  			p.addErrorAfter(pos, text[:lineStart+startPos], "invalid #cgo line: "+name)
 572  			continue
 573  		}
 574  	}
 575  	return text
 576  }
 577  
 578  // makeUnionField creates a new struct from an existing *elaboratedTypeInfo,
 579  // that has just a single field that must be accessed through special accessors.
 580  // It returns nil when there is an error. In case of an error, that error has
 581  // already been added to the list of errors using p.addError.
 582  func (p *cgoPackage) makeUnionField(typ *elaboratedTypeInfo) *ast.StructType {
 583  	unionFieldTypeName, ok := map[int64]string{
 584  		1: "uint8",
 585  		2: "uint16",
 586  		4: "uint32",
 587  		8: "uint64",
 588  	}[typ.unionAlign]
 589  	if !ok {
 590  		p.addError(typ.typeExpr.Struct, fmt.Sprintf("expected union alignment to be one of 1, 2, 4, or 8, but got %d", typ.unionAlign))
 591  		return nil
 592  	}
 593  	var unionFieldType ast.Expr = &ast.Ident{
 594  		NamePos: token.NoPos,
 595  		Name:    unionFieldTypeName,
 596  	}
 597  	if typ.unionSize != typ.unionAlign {
 598  		// A plain struct{uintX} isn't enough, we have to make a
 599  		// struct{[N]uintX} to make the union big enough.
 600  		if typ.unionSize/typ.unionAlign*typ.unionAlign != typ.unionSize {
 601  			p.addError(typ.typeExpr.Struct, fmt.Sprintf("union alignment (%d) must be a multiple of union alignment (%d)", typ.unionSize, typ.unionAlign))
 602  			return nil
 603  		}
 604  		unionFieldType = &ast.ArrayType{
 605  			Len: &ast.BasicLit{
 606  				Kind:  token.INT,
 607  				Value: strconv.FormatInt(typ.unionSize/typ.unionAlign, 10),
 608  			},
 609  			Elt: unionFieldType,
 610  		}
 611  	}
 612  	return &ast.StructType{
 613  		Struct: typ.typeExpr.Struct,
 614  		Fields: &ast.FieldList{
 615  			Opening: typ.typeExpr.Fields.Opening,
 616  			List: []*ast.Field{{
 617  				Names: []*ast.Ident{
 618  					{
 619  						NamePos: typ.typeExpr.Fields.Opening,
 620  						Name:    "$union",
 621  					},
 622  				},
 623  				Type: unionFieldType,
 624  			}},
 625  			Closing: typ.typeExpr.Fields.Closing,
 626  		},
 627  	}
 628  }
 629  
 630  // createUnionAccessor creates a function that returns a typed pointer to a
 631  // union field for each field in a union. For example:
 632  //
 633  //	func (union *C.union_1) unionfield_d() *float64 {
 634  //	    return (*float64)(unsafe.Pointer(&union.$union))
 635  //	}
 636  //
 637  // Where C.union_1 is defined as:
 638  //
 639  //	type C.union_1 struct{
 640  //	    $union uint64
 641  //	}
 642  //
 643  // The returned pointer can be used to get or set the field, or get the pointer
 644  // to a subfield.
 645  func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
 646  	if len(field.Names) != 1 {
 647  		panic("number of names in union field must be exactly 1")
 648  	}
 649  	fieldName := field.Names[0]
 650  	pos := fieldName.NamePos
 651  
 652  	// The method receiver.
 653  	receiver := &ast.SelectorExpr{
 654  		X: &ast.Ident{
 655  			NamePos: pos,
 656  			Name:    "union",
 657  			Obj:     nil,
 658  		},
 659  		Sel: &ast.Ident{
 660  			NamePos: pos,
 661  			Name:    "$union",
 662  		},
 663  	}
 664  
 665  	// Get the address of the $union field.
 666  	receiverPtr := &ast.UnaryExpr{
 667  		Op: token.AND,
 668  		X:  receiver,
 669  	}
 670  
 671  	// Cast to unsafe.Pointer.
 672  	sourcePointer := &ast.CallExpr{
 673  		Fun: &ast.SelectorExpr{
 674  			X:   &ast.Ident{Name: "unsafe"},
 675  			Sel: &ast.Ident{Name: "Pointer"},
 676  		},
 677  		Args: []ast.Expr{receiverPtr},
 678  	}
 679  
 680  	// Cast to the target pointer type.
 681  	targetPointer := &ast.CallExpr{
 682  		Lparen: pos,
 683  		Fun: &ast.ParenExpr{
 684  			Lparen: pos,
 685  			X: &ast.StarExpr{
 686  				X: field.Type,
 687  			},
 688  			Rparen: pos,
 689  		},
 690  		Args:   []ast.Expr{sourcePointer},
 691  		Rparen: pos,
 692  	}
 693  
 694  	// Create the accessor function.
 695  	accessor := &ast.FuncDecl{
 696  		Recv: &ast.FieldList{
 697  			Opening: pos,
 698  			List: []*ast.Field{
 699  				{
 700  					Names: []*ast.Ident{
 701  						{
 702  							NamePos: pos,
 703  							Name:    "union",
 704  						},
 705  					},
 706  					Type: &ast.StarExpr{
 707  						Star: pos,
 708  						X: &ast.Ident{
 709  							NamePos: pos,
 710  							Name:    typeName,
 711  							Obj:     nil,
 712  						},
 713  					},
 714  				},
 715  			},
 716  			Closing: pos,
 717  		},
 718  		Name: &ast.Ident{
 719  			NamePos: pos,
 720  			Name:    "unionfield_" + fieldName.Name,
 721  		},
 722  		Type: &ast.FuncType{
 723  			Func: pos,
 724  			Params: &ast.FieldList{
 725  				Opening: pos,
 726  				Closing: pos,
 727  			},
 728  			Results: &ast.FieldList{
 729  				List: []*ast.Field{
 730  					{
 731  						Type: &ast.StarExpr{
 732  							Star: pos,
 733  							X:    field.Type,
 734  						},
 735  					},
 736  				},
 737  			},
 738  		},
 739  		Body: &ast.BlockStmt{
 740  			Lbrace: pos,
 741  			List: []ast.Stmt{
 742  				&ast.ReturnStmt{
 743  					Return: pos,
 744  					Results: []ast.Expr{
 745  						targetPointer,
 746  					},
 747  				},
 748  			},
 749  			Rbrace: pos,
 750  		},
 751  	}
 752  	p.generated.Decls = append(p.generated.Decls, accessor)
 753  }
 754  
 755  // createBitfieldGetter creates a bitfield getter function like the following:
 756  //
 757  //	func (s *C.struct_foo) bitfield_b() byte {
 758  //	    return (s.__bitfield_1 >> 5) & 0x1
 759  //	}
 760  func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string) {
 761  	// The value to return from the getter.
 762  	// Not complete: this is just an expression to get the complete field.
 763  	var result ast.Expr = &ast.SelectorExpr{
 764  		X: &ast.Ident{
 765  			NamePos: bitfield.pos,
 766  			Name:    "s",
 767  			Obj:     nil,
 768  		},
 769  		Sel: &ast.Ident{
 770  			NamePos: bitfield.pos,
 771  			Name:    bitfield.field.Names[0].Name,
 772  		},
 773  	}
 774  	if bitfield.startBit != 0 {
 775  		// Shift to the right by .startBit so that fields that come before are
 776  		// shifted off.
 777  		result = &ast.BinaryExpr{
 778  			X:     result,
 779  			OpPos: bitfield.pos,
 780  			Op:    token.SHR,
 781  			Y: &ast.BasicLit{
 782  				ValuePos: bitfield.pos,
 783  				Kind:     token.INT,
 784  				Value:    strconv.FormatInt(bitfield.startBit, 10),
 785  			},
 786  		}
 787  	}
 788  	if bitfield.endBit != 0 {
 789  		// Mask off the high bits so that fields that come after this field are
 790  		// masked off.
 791  		and := (uint64(1) << uint64(bitfield.endBit-bitfield.startBit)) - 1
 792  		result = &ast.BinaryExpr{
 793  			X:     result,
 794  			OpPos: bitfield.pos,
 795  			Op:    token.AND,
 796  			Y: &ast.BasicLit{
 797  				ValuePos: bitfield.pos,
 798  				Kind:     token.INT,
 799  				Value:    "0x" + strconv.FormatUint(and, 16),
 800  			},
 801  		}
 802  	}
 803  
 804  	// Create the getter function.
 805  	getter := &ast.FuncDecl{
 806  		Recv: &ast.FieldList{
 807  			Opening: bitfield.pos,
 808  			List: []*ast.Field{
 809  				{
 810  					Names: []*ast.Ident{
 811  						{
 812  							NamePos: bitfield.pos,
 813  							Name:    "s",
 814  							Obj: &ast.Object{
 815  								Kind: ast.Var,
 816  								Name: "s",
 817  								Decl: nil,
 818  							},
 819  						},
 820  					},
 821  					Type: &ast.StarExpr{
 822  						Star: bitfield.pos,
 823  						X: &ast.Ident{
 824  							NamePos: bitfield.pos,
 825  							Name:    typeName,
 826  							Obj:     nil,
 827  						},
 828  					},
 829  				},
 830  			},
 831  			Closing: bitfield.pos,
 832  		},
 833  		Name: &ast.Ident{
 834  			NamePos: bitfield.pos,
 835  			Name:    "bitfield_" + bitfield.name,
 836  		},
 837  		Type: &ast.FuncType{
 838  			Func: bitfield.pos,
 839  			Params: &ast.FieldList{
 840  				Opening: bitfield.pos,
 841  				Closing: bitfield.pos,
 842  			},
 843  			Results: &ast.FieldList{
 844  				List: []*ast.Field{
 845  					{
 846  						Type: bitfield.field.Type,
 847  					},
 848  				},
 849  			},
 850  		},
 851  		Body: &ast.BlockStmt{
 852  			Lbrace: bitfield.pos,
 853  			List: []ast.Stmt{
 854  				&ast.ReturnStmt{
 855  					Return: bitfield.pos,
 856  					Results: []ast.Expr{
 857  						result,
 858  					},
 859  				},
 860  			},
 861  			Rbrace: bitfield.pos,
 862  		},
 863  	}
 864  	p.generated.Decls = append(p.generated.Decls, getter)
 865  }
 866  
 867  // createBitfieldSetter creates a bitfield setter function like the following:
 868  //
 869  //	func (s *C.struct_foo) set_bitfield_b(value byte) {
 870  //	    s.__bitfield_1 = s.__bitfield_1 ^ 0x60 | ((value & 1) << 5)
 871  //	}
 872  //
 873  // Or the following:
 874  //
 875  //	func (s *C.struct_foo) set_bitfield_c(value byte) {
 876  //	    s.__bitfield_1 = s.__bitfield_1 & 0x3f | (value << 6)
 877  //	}
 878  func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string) {
 879  	// The full field with all bitfields.
 880  	var field ast.Expr = &ast.SelectorExpr{
 881  		X: &ast.Ident{
 882  			NamePos: bitfield.pos,
 883  			Name:    "s",
 884  			Obj:     nil,
 885  		},
 886  		Sel: &ast.Ident{
 887  			NamePos: bitfield.pos,
 888  			Name:    bitfield.field.Names[0].Name,
 889  		},
 890  	}
 891  	// The value to insert into the field.
 892  	var valueToInsert ast.Expr = &ast.Ident{
 893  		NamePos: bitfield.pos,
 894  		Name:    "value",
 895  	}
 896  
 897  	if bitfield.endBit != 0 {
 898  		// Make sure the value is in range with a mask.
 899  		valueToInsert = &ast.BinaryExpr{
 900  			X:     valueToInsert,
 901  			OpPos: bitfield.pos,
 902  			Op:    token.AND,
 903  			Y: &ast.BasicLit{
 904  				ValuePos: bitfield.pos,
 905  				Kind:     token.INT,
 906  				Value:    "0x" + strconv.FormatUint((uint64(1)<<uint64(bitfield.endBit-bitfield.startBit))-1, 16),
 907  			},
 908  		}
 909  		// Create a mask for the AND NOT operation.
 910  		mask := ((uint64(1) << uint64(bitfield.endBit-bitfield.startBit)) - 1) << uint64(bitfield.startBit)
 911  		// Zero the bits in the field that will soon be inserted.
 912  		field = &ast.BinaryExpr{
 913  			X:     field,
 914  			OpPos: bitfield.pos,
 915  			Op:    token.AND_NOT,
 916  			Y: &ast.BasicLit{
 917  				ValuePos: bitfield.pos,
 918  				Kind:     token.INT,
 919  				Value:    "0x" + strconv.FormatUint(mask, 16),
 920  			},
 921  		}
 922  	} else { // bitfield.endBit == 0
 923  		// We don't know exactly how many high bits should be zeroed. So we do
 924  		// something different: keep the low bits with a mask and OR the new
 925  		// value with it.
 926  		mask := (uint64(1) << uint64(bitfield.startBit)) - 1
 927  		// Extract the lower bits.
 928  		field = &ast.BinaryExpr{
 929  			X:     field,
 930  			OpPos: bitfield.pos,
 931  			Op:    token.AND,
 932  			Y: &ast.BasicLit{
 933  				ValuePos: bitfield.pos,
 934  				Kind:     token.INT,
 935  				Value:    "0x" + strconv.FormatUint(mask, 16),
 936  			},
 937  		}
 938  	}
 939  
 940  	// Bitwise OR with the new value (after the new value has been shifted).
 941  	field = &ast.BinaryExpr{
 942  		X:     field,
 943  		OpPos: bitfield.pos,
 944  		Op:    token.OR,
 945  		Y: &ast.BinaryExpr{
 946  			X:     valueToInsert,
 947  			OpPos: bitfield.pos,
 948  			Op:    token.SHL,
 949  			Y: &ast.BasicLit{
 950  				ValuePos: bitfield.pos,
 951  				Kind:     token.INT,
 952  				Value:    strconv.FormatInt(bitfield.startBit, 10),
 953  			},
 954  		},
 955  	}
 956  
 957  	// Create the setter function.
 958  	setter := &ast.FuncDecl{
 959  		Recv: &ast.FieldList{
 960  			Opening: bitfield.pos,
 961  			List: []*ast.Field{
 962  				{
 963  					Names: []*ast.Ident{
 964  						{
 965  							NamePos: bitfield.pos,
 966  							Name:    "s",
 967  							Obj: &ast.Object{
 968  								Kind: ast.Var,
 969  								Name: "s",
 970  								Decl: nil,
 971  							},
 972  						},
 973  					},
 974  					Type: &ast.StarExpr{
 975  						Star: bitfield.pos,
 976  						X: &ast.Ident{
 977  							NamePos: bitfield.pos,
 978  							Name:    typeName,
 979  							Obj:     nil,
 980  						},
 981  					},
 982  				},
 983  			},
 984  			Closing: bitfield.pos,
 985  		},
 986  		Name: &ast.Ident{
 987  			NamePos: bitfield.pos,
 988  			Name:    "set_bitfield_" + bitfield.name,
 989  		},
 990  		Type: &ast.FuncType{
 991  			Func: bitfield.pos,
 992  			Params: &ast.FieldList{
 993  				Opening: bitfield.pos,
 994  				List: []*ast.Field{
 995  					{
 996  						Names: []*ast.Ident{
 997  							{
 998  								NamePos: bitfield.pos,
 999  								Name:    "value",
1000  								Obj:     nil,
1001  							},
1002  						},
1003  						Type: bitfield.field.Type,
1004  					},
1005  				},
1006  				Closing: bitfield.pos,
1007  			},
1008  		},
1009  		Body: &ast.BlockStmt{
1010  			Lbrace: bitfield.pos,
1011  			List: []ast.Stmt{
1012  				&ast.AssignStmt{
1013  					Lhs: []ast.Expr{
1014  						&ast.SelectorExpr{
1015  							X: &ast.Ident{
1016  								NamePos: bitfield.pos,
1017  								Name:    "s",
1018  								Obj:     nil,
1019  							},
1020  							Sel: &ast.Ident{
1021  								NamePos: bitfield.pos,
1022  								Name:    bitfield.field.Names[0].Name,
1023  							},
1024  						},
1025  					},
1026  					TokPos: bitfield.pos,
1027  					Tok:    token.ASSIGN,
1028  					Rhs: []ast.Expr{
1029  						field,
1030  					},
1031  				},
1032  			},
1033  			Rbrace: bitfield.pos,
1034  		},
1035  	}
1036  	p.generated.Decls = append(p.generated.Decls, setter)
1037  }
1038  
1039  // isEquivalentAST returns whether the given two AST nodes are equivalent as far
1040  // as CGo is concerned. This is used to check that C types, globals, etc defined
1041  // in different CGo header snippets are actually the same type (and probably
1042  // even defined in the same header file, just in different translation units).
1043  func (p *cgoPackage) isEquivalentAST(a, b ast.Node) bool {
1044  	switch node := a.(type) {
1045  	case *ast.ArrayType:
1046  		b, ok := b.(*ast.ArrayType)
1047  		if !ok {
1048  			return false
1049  		}
1050  		if !p.isEquivalentAST(node.Len, b.Len) {
1051  			return false
1052  		}
1053  		return p.isEquivalentAST(node.Elt, b.Elt)
1054  	case *ast.BasicLit:
1055  		b, ok := b.(*ast.BasicLit)
1056  		if !ok {
1057  			return false
1058  		}
1059  		// Note: this comparison is not correct in general ("1e2" equals "100"),
1060  		// but is correct for its use in the cgo package.
1061  		return node.Value == b.Value
1062  	case *ast.CommentGroup:
1063  		b, ok := b.(*ast.CommentGroup)
1064  		if !ok {
1065  			return false
1066  		}
1067  		if len(node.List) != len(b.List) {
1068  			return false
1069  		}
1070  		for i, c := range node.List {
1071  			if c.Text != b.List[i].Text {
1072  				return false
1073  			}
1074  		}
1075  		return true
1076  	case *ast.FieldList:
1077  		b, ok := b.(*ast.FieldList)
1078  		if !ok {
1079  			return false
1080  		}
1081  		if node == nil || b == nil {
1082  			return node == b
1083  		}
1084  		if len(node.List) != len(b.List) {
1085  			return false
1086  		}
1087  		for i, f := range node.List {
1088  			if !p.isEquivalentAST(f, b.List[i]) {
1089  				return false
1090  			}
1091  		}
1092  		return true
1093  	case *ast.Field:
1094  		b, ok := b.(*ast.Field)
1095  		if !ok {
1096  			return false
1097  		}
1098  		if !p.isEquivalentAST(node.Type, b.Type) {
1099  			return false
1100  		}
1101  		if len(node.Names) != len(b.Names) {
1102  			return false
1103  		}
1104  		for i, name := range node.Names {
1105  			if name.Name != b.Names[i].Name {
1106  				return false
1107  			}
1108  		}
1109  		return true
1110  	case *ast.FuncDecl:
1111  		b, ok := b.(*ast.FuncDecl)
1112  		if !ok {
1113  			return false
1114  		}
1115  		if node.Name.Name != b.Name.Name {
1116  			return false
1117  		}
1118  		if node.Doc != b.Doc {
1119  			if !p.isEquivalentAST(node.Doc, b.Doc) {
1120  				return false
1121  			}
1122  		}
1123  		if node.Recv != b.Recv {
1124  			if !p.isEquivalentAST(node.Recv, b.Recv) {
1125  				return false
1126  			}
1127  		}
1128  		if !p.isEquivalentAST(node.Type.Params, b.Type.Params) {
1129  			return false
1130  		}
1131  		return p.isEquivalentAST(node.Type.Results, b.Type.Results)
1132  	case *ast.GenDecl:
1133  		b, ok := b.(*ast.GenDecl)
1134  		if !ok {
1135  			return false
1136  		}
1137  		if node.Doc != b.Doc {
1138  			if !p.isEquivalentAST(node.Doc, b.Doc) {
1139  				return false
1140  			}
1141  		}
1142  		if len(node.Specs) != len(b.Specs) {
1143  			return false
1144  		}
1145  		for i, s := range node.Specs {
1146  			if !p.isEquivalentAST(s, b.Specs[i]) {
1147  				return false
1148  			}
1149  		}
1150  		return true
1151  	case *ast.Ident:
1152  		b, ok := b.(*ast.Ident)
1153  		if !ok {
1154  			return false
1155  		}
1156  		return node.Name == b.Name
1157  	case *ast.SelectorExpr:
1158  		b, ok := b.(*ast.SelectorExpr)
1159  		if !ok {
1160  			return false
1161  		}
1162  		if !p.isEquivalentAST(node.Sel, b.Sel) {
1163  			return false
1164  		}
1165  		return p.isEquivalentAST(node.X, b.X)
1166  	case *ast.StarExpr:
1167  		b, ok := b.(*ast.StarExpr)
1168  		if !ok {
1169  			return false
1170  		}
1171  		return p.isEquivalentAST(node.X, b.X)
1172  	case *ast.StructType:
1173  		b, ok := b.(*ast.StructType)
1174  		if !ok {
1175  			return false
1176  		}
1177  		return p.isEquivalentAST(node.Fields, b.Fields)
1178  	case *ast.TypeSpec:
1179  		b, ok := b.(*ast.TypeSpec)
1180  		if !ok {
1181  			return false
1182  		}
1183  		if node.Name.Name != b.Name.Name {
1184  			return false
1185  		}
1186  		if node.Assign.IsValid() != b.Assign.IsValid() {
1187  			return false
1188  		}
1189  		return p.isEquivalentAST(node.Type, b.Type)
1190  	case *ast.ValueSpec:
1191  		b, ok := b.(*ast.ValueSpec)
1192  		if !ok {
1193  			return false
1194  		}
1195  		if len(node.Names) != len(b.Names) {
1196  			return false
1197  		}
1198  		for i, name := range node.Names {
1199  			if name.Name != b.Names[i].Name {
1200  				return false
1201  			}
1202  		}
1203  		if node.Type != b.Type && !p.isEquivalentAST(node.Type, b.Type) {
1204  			return false
1205  		}
1206  		if len(node.Values) != len(b.Values) {
1207  			return false
1208  		}
1209  		for i, value := range node.Values {
1210  			if !p.isEquivalentAST(value, b.Values[i]) {
1211  				return false
1212  			}
1213  		}
1214  		return true
1215  	case nil:
1216  		p.addError(token.NoPos, "internal error: AST node is nil")
1217  		return true
1218  	default:
1219  		p.addError(a.Pos(), fmt.Sprintf("internal error: unknown AST node: %T", a))
1220  		return true
1221  	}
1222  }
1223  
1224  // getPos returns node.Pos(), and tries to obtain a closely related position if
1225  // that fails.
1226  func getPos(node ast.Node) token.Pos {
1227  	pos := node.Pos()
1228  	if pos.IsValid() {
1229  		return pos
1230  	}
1231  	if decl, ok := node.(*ast.GenDecl); ok {
1232  		// *ast.GenDecl often doesn't have TokPos defined, so look at the first
1233  		// spec.
1234  		return getPos(decl.Specs[0])
1235  	}
1236  	return token.NoPos
1237  }
1238  
1239  // getUnnamedDeclName creates a name (with the given prefix) for the given C
1240  // declaration. This is used for structs, unions, and enums that are often
1241  // defined without a name and used in a typedef.
1242  func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
1243  	if name, ok := p.anonDecls[itf]; ok {
1244  		return name
1245  	}
1246  	name := prefix + strconv.Itoa(len(p.anonDecls))
1247  	p.anonDecls[itf] = name
1248  	return name
1249  }
1250  
1251  // getASTDeclName will declare the given C AST node (if not already defined) and
1252  // will return its name, in the form of C.foo.
1253  func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string {
1254  	// Some types are defined in stdint.h and map directly to a particular Go
1255  	// type.
1256  	if alias := cgoAliases["_Cgo_"+name]; alias != "" {
1257  		return alias
1258  	}
1259  	node := f.getASTDeclNode(name, found)
1260  	if node, ok := node.(*ast.FuncDecl); ok {
1261  		if !iscall {
1262  			return node.Name.Name + "$funcaddr"
1263  		}
1264  		return node.Name.Name
1265  	}
1266  	return "_Cgo_" + name
1267  }
1268  
1269  // getASTDeclNode will declare the given C AST node (if not already defined) and
1270  // returns it.
1271  func (f *cgoFile) getASTDeclNode(name string, found clangCursor) ast.Node {
1272  	if node, ok := f.defined[name]; ok {
1273  		// Declaration was found in the current file, so return it immediately.
1274  		return node
1275  	}
1276  
1277  	if node, ok := f.definedGlobally[name]; ok {
1278  		// Declaration was previously created, but not for the current file. It
1279  		// may be different (because it comes from a different CGo snippet), so
1280  		// we need to check whether the AST for this definition is equivalent.
1281  		f.defined[name] = nil
1282  		newNode, _ := f.createASTNode(name, found)
1283  		if !f.isEquivalentAST(node, newNode) {
1284  			// It's not. Return a nice error with both locations.
1285  			// Original cgo reports an error like
1286  			//   cgo: inconsistent definitions for C.myint
1287  			// which is far less helpful.
1288  			f.addError(getPos(node), name+" defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
1289  		}
1290  		f.defined[name] = node
1291  		return node
1292  	}
1293  
1294  	// The declaration has no AST node. Create it now.
1295  	f.defined[name] = nil
1296  	node, extra := f.createASTNode(name, found)
1297  	f.defined[name] = node
1298  	switch node := node.(type) {
1299  	case *ast.FuncDecl:
1300  		if strings.HasPrefix(node.Doc.List[0].Text, "//export _Cgo_static_") {
1301  			// Static function. Only accessible in the current Go file.
1302  			globalName := strings.TrimPrefix(node.Doc.List[0].Text, "//export ")
1303  			// Make an alias. Normally this is done using the alias function
1304  			// attribute, but MacOS for some reason doesn't support this (even
1305  			// though the linker has support for aliases in the form of N_INDR).
1306  			// Therefore, create an actual function for MacOS.
1307  			var params []string
1308  			for _, param := range node.Type.Params.List {
1309  				params = append(params, param.Names[0].Name)
1310  			}
1311  			callInst := fmt.Sprintf("%s(%s);", name, strings.Join(params, ", "))
1312  			if node.Type.Results != nil {
1313  				callInst = "return " + callInst
1314  			}
1315  			aliasDeclaration := fmt.Sprintf(`
1316  #ifdef __APPLE__
1317  %s {
1318  	%s
1319  }
1320  #else
1321  extern __typeof(%s) %s __attribute__((alias(%#v)));
1322  #endif
1323  `, extra.(string), callInst, name, globalName, name)
1324  			f.cgoHeaders[f.index] += "\n\n" + aliasDeclaration
1325  		} else {
1326  			// Regular (non-static) function.
1327  			f.definedGlobally[name] = node
1328  		}
1329  		f.generated.Decls = append(f.generated.Decls, node)
1330  		// Also add a declaration like the following:
1331  		//   var C.foo$funcaddr unsafe.Pointer
1332  		f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
1333  			Tok: token.VAR,
1334  			Specs: []ast.Spec{
1335  				&ast.ValueSpec{
1336  					Names: []*ast.Ident{{Name: node.Name.Name + "$funcaddr"}},
1337  					Type: &ast.SelectorExpr{
1338  						X:   &ast.Ident{Name: "unsafe"},
1339  						Sel: &ast.Ident{Name: "Pointer"},
1340  					},
1341  				},
1342  			},
1343  		})
1344  	case *ast.GenDecl:
1345  		f.definedGlobally[name] = node
1346  		f.generated.Decls = append(f.generated.Decls, node)
1347  	case *ast.TypeSpec:
1348  		f.definedGlobally[name] = node
1349  		f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
1350  			Tok:   token.TYPE,
1351  			Specs: []ast.Spec{node},
1352  		})
1353  	case nil:
1354  		// Node may be nil in case of an error. In that case, just don't add it
1355  		// as a declaration.
1356  	default:
1357  		panic("unexpected AST node")
1358  	}
1359  
1360  	// If this is a struct or union it may need bitfields or union accessor
1361  	// methods.
1362  	switch elaboratedType := extra.(type) {
1363  	case *elaboratedTypeInfo:
1364  		// Add struct bitfields.
1365  		for _, bitfield := range elaboratedType.bitfields {
1366  			f.createBitfieldGetter(bitfield, "_Cgo_"+name)
1367  			f.createBitfieldSetter(bitfield, "_Cgo_"+name)
1368  		}
1369  		if elaboratedType.unionSize != 0 {
1370  			// Create union getters/setters.
1371  			for _, field := range elaboratedType.typeExpr.Fields.List {
1372  				if len(field.Names) != 1 {
1373  					f.addError(elaboratedType.pos, fmt.Sprintf("union must have field with a single name, it has %d names", len(field.Names)))
1374  					continue
1375  				}
1376  				f.createUnionAccessor(field, "_Cgo_"+name)
1377  			}
1378  		}
1379  	}
1380  
1381  	return node
1382  }
1383  
1384  // walker replaces all "C".<something> expressions to literal "C.<something>"
1385  // expressions. Such expressions are impossible to write in Go (a dot cannot be
1386  // used in the middle of a name) so in practice all C identifiers live in a
1387  // separate namespace (no _Cgo_ hacks like in gc).
1388  func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) bool {
1389  	switch node := cursor.Node().(type) {
1390  	case *ast.AssignStmt:
1391  		// An assign statement could be something like this:
1392  		//
1393  		//   val, errno := C.some_func()
1394  		//
1395  		// Check whether it looks like that, and if so, read the errno value and
1396  		// return it as the second return value. The call will be transformed
1397  		// into something like this:
1398  		//
1399  		//   val, errno := C.some_func(), C.__get_errno()
1400  		if len(node.Lhs) != 2 || len(node.Rhs) != 1 {
1401  			return true
1402  		}
1403  		rhs, ok := node.Rhs[0].(*ast.CallExpr)
1404  		if !ok {
1405  			return true
1406  		}
1407  		fun, ok := rhs.Fun.(*ast.SelectorExpr)
1408  		if !ok {
1409  			return true
1410  		}
1411  		x, ok := fun.X.(*ast.Ident)
1412  		if !ok {
1413  			return true
1414  		}
1415  		if found, ok := names[fun.Sel.Name]; ok && x.Name == "C" {
1416  			// Replace "C"."some_func" into "C.somefunc".
1417  			rhs.Fun = &ast.Ident{
1418  				NamePos: x.NamePos,
1419  				Name:    f.getASTDeclName(fun.Sel.Name, found, true),
1420  			}
1421  			// Add the errno value as the second value in the statement.
1422  			node.Rhs = append(node.Rhs, &ast.CallExpr{
1423  				Fun: &ast.Ident{
1424  					NamePos: node.Lhs[1].End(),
1425  					Name:    "_Cgo___get_errno",
1426  				},
1427  			})
1428  		}
1429  	case *ast.CallExpr:
1430  		fun, ok := node.Fun.(*ast.SelectorExpr)
1431  		if !ok {
1432  			return true
1433  		}
1434  		x, ok := fun.X.(*ast.Ident)
1435  		if !ok {
1436  			return true
1437  		}
1438  		if found, ok := names[fun.Sel.Name]; ok && x.Name == "C" {
1439  			node.Fun = &ast.Ident{
1440  				NamePos: x.NamePos,
1441  				Name:    f.getASTDeclName(fun.Sel.Name, found, true),
1442  			}
1443  		}
1444  	case *ast.SelectorExpr:
1445  		x, ok := node.X.(*ast.Ident)
1446  		if !ok {
1447  			return true
1448  		}
1449  		if x.Name == "C" {
1450  			name := "_Cgo_" + node.Sel.Name
1451  			if found, ok := names[node.Sel.Name]; ok {
1452  				name = f.getASTDeclName(node.Sel.Name, found, false)
1453  			}
1454  			cursor.Replace(&ast.Ident{
1455  				NamePos: x.NamePos,
1456  				Name:    name,
1457  			})
1458  		}
1459  	}
1460  	return true
1461  }
1462  
1463  // renameFieldKeywords renames all reserved words in Go to some other field name
1464  // with a "_" prefix. For example, it renames `type` to `_type`.
1465  //
1466  // See: https://golang.org/cmd/cgo/#hdr-Go_references_to_C
1467  func renameFieldKeywords(fieldList *ast.FieldList) {
1468  	renameFieldName(fieldList, "type")
1469  }
1470  
1471  // renameFieldName renames a given field name to a name with a "_" prepended. It
1472  // makes sure to do the same thing for any field sharing the same name.
1473  func renameFieldName(fieldList *ast.FieldList, name string) {
1474  	var ident *ast.Ident
1475  	for _, f := range fieldList.List {
1476  		for _, n := range f.Names {
1477  			if n.Name == name {
1478  				ident = n
1479  			}
1480  		}
1481  	}
1482  	if ident == nil {
1483  		return
1484  	}
1485  	renameFieldName(fieldList, "_"+name)
1486  	ident.Name = "_" + ident.Name
1487  }
1488