libclang.go raw

   1  package cgo
   2  
   3  // This file parses a fragment of C with libclang and stores the result for AST
   4  // modification. It does not touch the AST itself.
   5  
   6  import (
   7  	"bytes"
   8  	"crypto/sha256"
   9  	"crypto/sha512"
  10  	"encoding/hex"
  11  	"fmt"
  12  	"go/ast"
  13  	"go/scanner"
  14  	"go/token"
  15  	"path/filepath"
  16  	"strconv"
  17  	"strings"
  18  	"unsafe"
  19  
  20  	"tinygo.org/x/go-llvm"
  21  )
  22  
  23  /*
  24  #include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://moxie.dev/docs/guides/build/
  25  #include <llvm/Config/llvm-config.h>
  26  #include <stdlib.h>
  27  #include <stdint.h>
  28  
  29  // This struct should be ABI-compatible on all platforms (uintptr_t has the same
  30  // alignment etc. as void*) but does not include void* pointers that are not
  31  // always real pointers.
  32  // The Go garbage collector assumes that all non-nil pointer-typed integers are
  33  // actually pointers. This is not always true, as data[1] often contains 0x1,
  34  // which is clearly not a valid pointer. Usually the GC won't catch this issue,
  35  // but occasionally it will leading to a crash with a vague error message.
  36  typedef struct {
  37  	enum CXCursorKind kind;
  38  	int xdata;
  39  	uintptr_t data[3];
  40  } GoCXCursor;
  41  
  42  // Forwarding functions. They are implemented in libclang_stubs.c and forward to
  43  // the real functions without doing anything else, thus they are entirely
  44  // compatible with the versions without moxie_ prefix. The only difference is
  45  // the CXCursor type, which has been replaced with GoCXCursor.
  46  GoCXCursor moxie_clang_getTranslationUnitCursor(CXTranslationUnit tu);
  47  unsigned moxie_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
  48  CXString moxie_clang_getCursorSpelling(GoCXCursor c);
  49  CXString moxie_clang_getCursorPrettyPrinted(GoCXCursor c, CXPrintingPolicy Policy);
  50  CXPrintingPolicy moxie_clang_getCursorPrintingPolicy(GoCXCursor c);
  51  enum CXCursorKind moxie_clang_getCursorKind(GoCXCursor c);
  52  CXType moxie_clang_getCursorType(GoCXCursor c);
  53  GoCXCursor moxie_clang_getTypeDeclaration(CXType t);
  54  CXType moxie_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
  55  CXType moxie_clang_getCursorResultType(GoCXCursor c);
  56  int moxie_clang_Cursor_getNumArguments(GoCXCursor c);
  57  GoCXCursor moxie_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
  58  enum CX_StorageClass moxie_clang_Cursor_getStorageClass(GoCXCursor c);
  59  CXSourceLocation moxie_clang_getCursorLocation(GoCXCursor c);
  60  CXSourceRange moxie_clang_getCursorExtent(GoCXCursor c);
  61  CXTranslationUnit moxie_clang_Cursor_getTranslationUnit(GoCXCursor c);
  62  long long moxie_clang_getEnumConstantDeclValue(GoCXCursor c);
  63  CXType moxie_clang_getEnumDeclIntegerType(GoCXCursor c);
  64  unsigned moxie_clang_Cursor_isAnonymous(GoCXCursor c);
  65  unsigned moxie_clang_Cursor_isBitField(GoCXCursor c);
  66  unsigned moxie_clang_Cursor_isMacroFunctionLike(GoCXCursor c);
  67  
  68  // Fix some warnings on Windows ARM. Without the __declspec(dllexport), it gives warnings like this:
  69  //     In file included from _cgo_export.c:4:
  70  //     cgo-gcc-export-header-prolog:49:34: warning: redeclaration of 'moxie_clang_globals_visitor' should not add 'dllexport' attribute [-Wdll-attribute-on-redeclaration]
  71  //     libclang.go:68:5: note: previous declaration is here
  72  // See: https://github.com/golang/go/issues/49721
  73  #if defined(_WIN32)
  74  #define CGO_DECL __declspec(dllexport)
  75  #else
  76  #define CGO_DECL
  77  #endif
  78  
  79  CGO_DECL
  80  int moxie_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
  81  CGO_DECL
  82  int moxie_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
  83  CGO_DECL
  84  void moxie_clang_inclusion_visitor(CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data);
  85  */
  86  import "C"
  87  
  88  // storedRefs stores references to types, used for clang_visitChildren.
  89  var storedRefs refMap
  90  
  91  var diagnosticSeverity = [...]string{
  92  	C.CXDiagnostic_Ignored: "ignored",
  93  	C.CXDiagnostic_Note:    "note",
  94  	C.CXDiagnostic_Warning: "warning",
  95  	C.CXDiagnostic_Error:   "error",
  96  	C.CXDiagnostic_Fatal:   "fatal",
  97  }
  98  
  99  // Alias so that cgo.go (which doesn't import Clang related stuff and is in
 100  // theory decoupled from Clang) can also use this type.
 101  type clangCursor = C.GoCXCursor
 102  
 103  func init() {
 104  	// Check that we haven't messed up LLVM versioning.
 105  	// This can happen when llvm_config_*.go files in either this or the
 106  	// tinygo.org/x/go-llvm package are incorrect. It should not ever happen
 107  	// with byollvm.
 108  	if C.LLVM_VERSION_STRING != llvm.Version {
 109  		panic("incorrect build: using LLVM version " + llvm.Version + " in the tinygo.org/x/go-llvm package, and version " + C.LLVM_VERSION_STRING + " in the ./cgo package")
 110  	}
 111  }
 112  
 113  func (f *cgoFile) readNames(fragment string, cflags []string, filename string, callback func(map[string]clangCursor)) {
 114  	index := C.clang_createIndex(0, 0)
 115  	defer C.clang_disposeIndex(index)
 116  
 117  	// pretend to be a .c file
 118  	filenameC := C.CString(filename + "!cgo.c")
 119  	defer C.free(unsafe.Pointer(filenameC))
 120  
 121  	fragmentC := C.CString(fragment)
 122  	defer C.free(unsafe.Pointer(fragmentC))
 123  
 124  	unsavedFile := C.struct_CXUnsavedFile{
 125  		Filename: filenameC,
 126  		Length:   C.ulong(len(fragment)),
 127  		Contents: fragmentC,
 128  	}
 129  
 130  	// convert Go slice of strings to C array of strings.
 131  	cmdargsC := C.malloc(C.size_t(len(cflags)) * C.size_t(unsafe.Sizeof(uintptr(0))))
 132  	defer C.free(cmdargsC)
 133  	cmdargs := (*[1 << 16]*C.char)(cmdargsC)
 134  	for i, cflag := range cflags {
 135  		s := C.CString(cflag)
 136  		cmdargs[i] = s
 137  		defer C.free(unsafe.Pointer(s))
 138  	}
 139  
 140  	var unit C.CXTranslationUnit
 141  	errCode := C.clang_parseTranslationUnit2(
 142  		index,
 143  		filenameC,
 144  		(**C.char)(cmdargsC), C.int(len(cflags)), // command line args
 145  		&unsavedFile, 1, // unsaved files
 146  		C.CXTranslationUnit_DetailedPreprocessingRecord,
 147  		&unit)
 148  	if errCode != 0 {
 149  		// This is probably a bug in the usage of libclang.
 150  		panic("cgo: failed to parse source with libclang")
 151  	}
 152  	defer C.clang_disposeTranslationUnit(unit)
 153  
 154  	// Report parser and type errors.
 155  	if numDiagnostics := int(C.clang_getNumDiagnostics(unit)); numDiagnostics != 0 {
 156  		addDiagnostic := func(diagnostic C.CXDiagnostic) {
 157  			spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
 158  			severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
 159  			location := C.clang_getDiagnosticLocation(diagnostic)
 160  			pos := f.getClangLocationPosition(location, unit)
 161  			f.addError(pos, severity+": "+spelling)
 162  		}
 163  		for i := 0; i < numDiagnostics; i++ {
 164  			diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
 165  			addDiagnostic(diagnostic)
 166  
 167  			// Child diagnostics (like notes on redefinitions).
 168  			diagnostics := C.clang_getChildDiagnostics(diagnostic)
 169  			for j := 0; j < int(C.clang_getNumDiagnosticsInSet(diagnostics)); j++ {
 170  				addDiagnostic(C.clang_getDiagnosticInSet(diagnostics, C.uint(j)))
 171  			}
 172  		}
 173  	}
 174  
 175  	// Extract information required by CGo.
 176  	ref := storedRefs.Put(f)
 177  	defer storedRefs.Remove(ref)
 178  	cursor := C.moxie_clang_getTranslationUnitCursor(unit)
 179  	C.moxie_clang_visitChildren(cursor, C.CXCursorVisitor(C.moxie_clang_globals_visitor), C.CXClientData(ref))
 180  
 181  	// Determine files read during CGo processing, for caching.
 182  	inclusionCallback := func(includedFile C.CXFile) {
 183  		// Get full file path.
 184  		path := getString(C.clang_getFileName(includedFile))
 185  
 186  		// Get contents of file (that should be in-memory).
 187  		size := C.size_t(0)
 188  		rawData := C.clang_getFileContents(unit, includedFile, &size)
 189  		if rawData == nil {
 190  			// Sanity check. This should (hopefully) never trigger.
 191  			panic("libclang: file contents was not loaded")
 192  		}
 193  		data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
 194  
 195  		// Hash the contents if it isn't hashed yet.
 196  		if _, ok := f.visitedFiles[path]; !ok {
 197  			// already stored
 198  			sum := sha512.Sum512_224(data)
 199  			f.visitedFiles[path] = sum[:]
 200  		}
 201  	}
 202  	inclusionCallbackRef := storedRefs.Put(inclusionCallback)
 203  	defer storedRefs.Remove(inclusionCallbackRef)
 204  	C.clang_getInclusions(unit, C.CXInclusionVisitor(C.moxie_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef))
 205  
 206  	// Do all the C AST operations inside a callback. This makes sure that
 207  	// libclang related memory is only freed after it is not necessary anymore.
 208  	callback(f.names)
 209  }
 210  
 211  // Convert the AST node under the given Clang cursor to a Go AST node and return
 212  // it.
 213  func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
 214  	kind := C.moxie_clang_getCursorKind(c)
 215  	pos := f.getCursorPosition(c)
 216  	switch kind {
 217  	case C.CXCursor_FunctionDecl:
 218  		cursorType := C.moxie_clang_getCursorType(c)
 219  		numArgs := int(C.moxie_clang_Cursor_getNumArguments(c))
 220  		obj := &ast.Object{
 221  			Kind: ast.Fun,
 222  			Name: "_Cgo_" + name,
 223  		}
 224  		exportName := name
 225  		localName := name
 226  		var stringSignature string
 227  		if C.moxie_clang_Cursor_getStorageClass(c) == C.CX_SC_Static {
 228  			// A static function is assigned a globally unique symbol name based
 229  			// on the file path (like _Cgo_static_2d09198adbf58f4f4655_foo) and
 230  			// has a different Go name in the form of C.foo!symbols.go instead
 231  			// of just C.foo.
 232  			path := f.importPath + "/" + filepath.Base(f.fset.File(f.file.Pos()).Name())
 233  			staticIDBuf := sha256.Sum256([]byte(path))
 234  			staticID := hex.EncodeToString(staticIDBuf[:10])
 235  			exportName = "_Cgo_static_" + staticID + "_" + name
 236  			localName = name + "!" + filepath.Base(path)
 237  
 238  			// Create a signature. This is necessary for MacOS to forward the
 239  			// call, because MacOS doesn't support aliases like ELF and PE do.
 240  			// (There is N_INDR but __attribute__((alias("..."))) doesn't work).
 241  			policy := C.moxie_clang_getCursorPrintingPolicy(c)
 242  			defer C.clang_PrintingPolicy_dispose(policy)
 243  			C.clang_PrintingPolicy_setProperty(policy, C.CXPrintingPolicy_TerseOutput, 1)
 244  			stringSignature = getString(C.moxie_clang_getCursorPrettyPrinted(c, policy))
 245  			stringSignature = strings.Replace(stringSignature, " "+name+"(", " "+exportName+"(", 1)
 246  			stringSignature = strings.TrimPrefix(stringSignature, "static ")
 247  		}
 248  		args := make([]*ast.Field, numArgs)
 249  		decl := &ast.FuncDecl{
 250  			Doc: &ast.CommentGroup{
 251  				List: []*ast.Comment{
 252  					{
 253  						Slash: pos - 1,
 254  						Text:  "//export " + exportName,
 255  					},
 256  				},
 257  			},
 258  			Name: &ast.Ident{
 259  				NamePos: pos,
 260  				Name:    "_Cgo_" + localName,
 261  				Obj:     obj,
 262  			},
 263  			Type: &ast.FuncType{
 264  				Func: pos,
 265  				Params: &ast.FieldList{
 266  					Opening: pos,
 267  					List:    args,
 268  					Closing: pos,
 269  				},
 270  			},
 271  		}
 272  		var doc []string
 273  		if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
 274  			doc = append(doc, "//go:variadic")
 275  		}
 276  		if _, ok := f.noescapingFuncs[name]; ok {
 277  			doc = append(doc, "//go:noescape")
 278  			f.noescapingFuncs[name].used = true
 279  		}
 280  		if len(doc) != 0 {
 281  			decl.Doc.List = append(decl.Doc.List, &ast.Comment{
 282  				Slash: pos - 1,
 283  				Text:  strings.Join(doc, "\n"),
 284  			})
 285  		}
 286  		for i := 0; i < numArgs; i++ {
 287  			arg := C.moxie_clang_Cursor_getArgument(c, C.uint(i))
 288  			argName := getString(C.moxie_clang_getCursorSpelling(arg))
 289  			argType := C.clang_getArgType(cursorType, C.uint(i))
 290  			if argName == "" {
 291  				argName = "$" + strconv.Itoa(i)
 292  			}
 293  			args[i] = &ast.Field{
 294  				Names: []*ast.Ident{
 295  					{
 296  						NamePos: pos,
 297  						Name:    argName,
 298  						Obj: &ast.Object{
 299  							Kind: ast.Var,
 300  							Name: argName,
 301  							Decl: decl,
 302  						},
 303  					},
 304  				},
 305  				Type: f.makeDecayingASTType(argType, pos),
 306  			}
 307  		}
 308  		resultType := C.moxie_clang_getCursorResultType(c)
 309  		if resultType.kind != C.CXType_Void {
 310  			decl.Type.Results = &ast.FieldList{
 311  				List: []*ast.Field{
 312  					{
 313  						Type: f.makeASTType(resultType, pos),
 314  					},
 315  				},
 316  			}
 317  		}
 318  		obj.Decl = decl
 319  		return decl, stringSignature
 320  	case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
 321  		typ := f.makeASTRecordType(c, pos)
 322  		typeName := "_Cgo_" + name
 323  		typeExpr := typ.typeExpr
 324  		if typ.unionSize != 0 {
 325  			// Convert to a single-field struct type.
 326  			typeExpr = f.makeUnionField(typ)
 327  		}
 328  		obj := &ast.Object{
 329  			Kind: ast.Typ,
 330  			Name: typeName,
 331  		}
 332  		typeSpec := &ast.TypeSpec{
 333  			Name: &ast.Ident{
 334  				NamePos: typ.pos,
 335  				Name:    typeName,
 336  				Obj:     obj,
 337  			},
 338  			Type: typeExpr,
 339  		}
 340  		obj.Decl = typeSpec
 341  		return typeSpec, typ
 342  	case C.CXCursor_TypedefDecl:
 343  		typeName := "_Cgo_" + name
 344  		underlyingType := C.moxie_clang_getTypedefDeclUnderlyingType(c)
 345  		obj := &ast.Object{
 346  			Kind: ast.Typ,
 347  			Name: typeName,
 348  		}
 349  		typeSpec := &ast.TypeSpec{
 350  			Name: &ast.Ident{
 351  				NamePos: pos,
 352  				Name:    typeName,
 353  				Obj:     obj,
 354  			},
 355  			Type: f.makeASTType(underlyingType, pos),
 356  		}
 357  		if underlyingType.kind != C.CXType_Enum {
 358  			typeSpec.Assign = pos
 359  		}
 360  		obj.Decl = typeSpec
 361  		return typeSpec, nil
 362  	case C.CXCursor_VarDecl:
 363  		cursorType := C.moxie_clang_getCursorType(c)
 364  		typeExpr := f.makeASTType(cursorType, pos)
 365  		gen := &ast.GenDecl{
 366  			TokPos: pos,
 367  			Tok:    token.VAR,
 368  			Lparen: token.NoPos,
 369  			Rparen: token.NoPos,
 370  			Doc: &ast.CommentGroup{
 371  				List: []*ast.Comment{
 372  					{
 373  						Slash: pos - 1,
 374  						Text:  "//go:extern " + name,
 375  					},
 376  				},
 377  			},
 378  		}
 379  		obj := &ast.Object{
 380  			Kind: ast.Var,
 381  			Name: "_Cgo_" + name,
 382  		}
 383  		valueSpec := &ast.ValueSpec{
 384  			Names: []*ast.Ident{{
 385  				NamePos: pos,
 386  				Name:    "_Cgo_" + name,
 387  				Obj:     obj,
 388  			}},
 389  			Type: typeExpr,
 390  		}
 391  		obj.Decl = valueSpec
 392  		gen.Specs = append(gen.Specs, valueSpec)
 393  		return gen, nil
 394  	case C.CXCursor_MacroDefinition:
 395  		tokenPos, value := f.getMacro(c)
 396  		expr, scannerError := parseConst(tokenPos, f.fset, value, nil, token.NoPos, f)
 397  		if scannerError != nil {
 398  			f.errors = append(f.errors, *scannerError)
 399  			return nil, nil
 400  		}
 401  
 402  		gen := &ast.GenDecl{
 403  			TokPos: token.NoPos,
 404  			Tok:    token.CONST,
 405  			Lparen: token.NoPos,
 406  			Rparen: token.NoPos,
 407  		}
 408  		obj := &ast.Object{
 409  			Kind: ast.Con,
 410  			Name: "_Cgo_" + name,
 411  		}
 412  		valueSpec := &ast.ValueSpec{
 413  			Names: []*ast.Ident{{
 414  				NamePos: pos,
 415  				Name:    "_Cgo_" + name,
 416  				Obj:     obj,
 417  			}},
 418  			Values: []ast.Expr{expr},
 419  		}
 420  		obj.Decl = valueSpec
 421  		gen.Specs = append(gen.Specs, valueSpec)
 422  		return gen, nil
 423  	case C.CXCursor_EnumDecl:
 424  		obj := &ast.Object{
 425  			Kind: ast.Typ,
 426  			Name: "_Cgo_" + name,
 427  		}
 428  		underlying := C.moxie_clang_getEnumDeclIntegerType(c)
 429  		// TODO: gc's CGo implementation uses types such as `uint32` for enums
 430  		// instead of types such as C.int, which are used here.
 431  		typeSpec := &ast.TypeSpec{
 432  			Name: &ast.Ident{
 433  				NamePos: pos,
 434  				Name:    "_Cgo_" + name,
 435  				Obj:     obj,
 436  			},
 437  			Assign: pos,
 438  			Type:   f.makeASTType(underlying, pos),
 439  		}
 440  		obj.Decl = typeSpec
 441  		return typeSpec, nil
 442  	case C.CXCursor_EnumConstantDecl:
 443  		value := C.moxie_clang_getEnumConstantDeclValue(c)
 444  		expr := &ast.BasicLit{
 445  			ValuePos: pos,
 446  			Kind:     token.INT,
 447  			Value:    strconv.FormatInt(int64(value), 10),
 448  		}
 449  		gen := &ast.GenDecl{
 450  			TokPos: token.NoPos,
 451  			Tok:    token.CONST,
 452  			Lparen: token.NoPos,
 453  			Rparen: token.NoPos,
 454  		}
 455  		obj := &ast.Object{
 456  			Kind: ast.Con,
 457  			Name: "_Cgo_" + name,
 458  		}
 459  		valueSpec := &ast.ValueSpec{
 460  			Names: []*ast.Ident{{
 461  				NamePos: pos,
 462  				Name:    "_Cgo_" + name,
 463  				Obj:     obj,
 464  			}},
 465  			Values: []ast.Expr{expr},
 466  		}
 467  		obj.Decl = valueSpec
 468  		gen.Specs = append(gen.Specs, valueSpec)
 469  		return gen, nil
 470  	default:
 471  		f.addError(pos, fmt.Sprintf("internal error: unknown cursor type: %d", kind))
 472  		return nil, nil
 473  	}
 474  }
 475  
 476  // Return whether this is a macro that's also function-like, like this:
 477  //
 478  //	#define add(a, b) (a+b)
 479  func (f *cgoFile) isFunctionLikeMacro(c clangCursor) bool {
 480  	if C.moxie_clang_getCursorKind(c) != C.CXCursor_MacroDefinition {
 481  		return false
 482  	}
 483  	return C.moxie_clang_Cursor_isMacroFunctionLike(c) != 0
 484  }
 485  
 486  // Get the macro value: the position in the source file and the string value of
 487  // the macro.
 488  func (f *cgoFile) getMacro(c clangCursor) (pos token.Pos, value string) {
 489  	// Extract tokens from the Clang tokenizer.
 490  	// See: https://stackoverflow.com/a/19074846/559350
 491  	sourceRange := C.moxie_clang_getCursorExtent(c)
 492  	tu := C.moxie_clang_Cursor_getTranslationUnit(c)
 493  	var rawTokens *C.CXToken
 494  	var numTokens C.unsigned
 495  	C.clang_tokenize(tu, sourceRange, &rawTokens, &numTokens)
 496  	tokens := unsafe.Slice(rawTokens, numTokens)
 497  	defer C.clang_disposeTokens(tu, rawTokens, numTokens)
 498  
 499  	// Convert this range of tokens back to source text.
 500  	// Ugly, but it works well enough.
 501  	sourceBuf := &bytes.Buffer{}
 502  	var startOffset int
 503  	for i, token := range tokens {
 504  		spelling := getString(C.clang_getTokenSpelling(tu, token))
 505  		location := C.clang_getTokenLocation(tu, token)
 506  		var tokenOffset C.unsigned
 507  		C.clang_getExpansionLocation(location, nil, nil, nil, &tokenOffset)
 508  		if i == 0 {
 509  			// The first token is the macro name itself.
 510  			// Skip it (after using its location).
 511  			startOffset = int(tokenOffset)
 512  		} else {
 513  			// Later tokens are the macro contents.
 514  			for int(tokenOffset) > (startOffset + sourceBuf.Len()) {
 515  				// Pad the source text with whitespace (that must have been
 516  				// present in the original source as well).
 517  				sourceBuf.WriteByte(' ')
 518  			}
 519  			sourceBuf.WriteString(spelling)
 520  		}
 521  	}
 522  	value = sourceBuf.String()
 523  
 524  	// Obtain the position of this token. This is the position of the first
 525  	// character in the 'value' string and is used to report errors at the
 526  	// correct location in the source file.
 527  	pos = f.getCursorPosition(c)
 528  
 529  	return
 530  }
 531  
 532  func getString(clangString C.CXString) (s string) {
 533  	rawString := C.clang_getCString(clangString)
 534  	s = C.GoString(rawString)
 535  	C.clang_disposeString(clangString)
 536  	return
 537  }
 538  
 539  //export moxie_clang_globals_visitor
 540  func moxie_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
 541  	f := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoFile)
 542  	switch C.moxie_clang_getCursorKind(c) {
 543  	case C.CXCursor_FunctionDecl:
 544  		name := getString(C.moxie_clang_getCursorSpelling(c))
 545  		f.names[name] = c
 546  	case C.CXCursor_StructDecl:
 547  		name := getString(C.moxie_clang_getCursorSpelling(c))
 548  		if name != "" {
 549  			f.names["struct_"+name] = c
 550  		}
 551  	case C.CXCursor_UnionDecl:
 552  		name := getString(C.moxie_clang_getCursorSpelling(c))
 553  		if name != "" {
 554  			f.names["union_"+name] = c
 555  		}
 556  	case C.CXCursor_TypedefDecl:
 557  		typedefType := C.moxie_clang_getCursorType(c)
 558  		name := getString(C.clang_getTypedefName(typedefType))
 559  		f.names[name] = c
 560  	case C.CXCursor_VarDecl:
 561  		name := getString(C.moxie_clang_getCursorSpelling(c))
 562  		f.names[name] = c
 563  	case C.CXCursor_MacroDefinition:
 564  		name := getString(C.moxie_clang_getCursorSpelling(c))
 565  		f.names[name] = c
 566  	case C.CXCursor_EnumDecl:
 567  		name := getString(C.moxie_clang_getCursorSpelling(c))
 568  		if name != "" {
 569  			// Named enum, which can be referenced from Go using C.enum_foo.
 570  			f.names["enum_"+name] = c
 571  		}
 572  		// The enum fields are in global scope, so recurse to visit them.
 573  		return C.CXChildVisit_Recurse
 574  	case C.CXCursor_EnumConstantDecl:
 575  		// We arrive here because of the "Recurse" above.
 576  		name := getString(C.moxie_clang_getCursorSpelling(c))
 577  		f.names[name] = c
 578  	}
 579  	return C.CXChildVisit_Continue
 580  }
 581  
 582  // Get the precise location in the source code. Used for uniquely identifying
 583  // source locations.
 584  func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) interface{} {
 585  	clangLocation := C.moxie_clang_getCursorLocation(cursor)
 586  	var file C.CXFile
 587  	var line C.unsigned
 588  	var column C.unsigned
 589  	C.clang_getFileLocation(clangLocation, &file, &line, &column, nil)
 590  	location := token.Position{
 591  		Filename: getString(C.clang_getFileName(file)),
 592  		Line:     int(line),
 593  		Column:   int(column),
 594  	}
 595  	if location.Filename == "" || location.Line == 0 {
 596  		// Not sure when this would happen, but protect from it anyway.
 597  		f.addError(pos, "could not find file/line information")
 598  	}
 599  	return location
 600  }
 601  
 602  // getCursorPosition returns a usable token.Pos from a libclang cursor.
 603  func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
 604  	return p.getClangLocationPosition(C.moxie_clang_getCursorLocation(cursor), C.moxie_clang_Cursor_getTranslationUnit(cursor))
 605  }
 606  
 607  // getClangLocationPosition returns a usable token.Pos based on a libclang
 608  // location and translation unit. If the file for this cursor has not been seen
 609  // before, it is read from libclang (which already has the file in memory) and
 610  // added to the token.FileSet.
 611  func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.CXTranslationUnit) token.Pos {
 612  	var file C.CXFile
 613  	var line C.unsigned
 614  	var column C.unsigned
 615  	var offset C.unsigned
 616  	C.clang_getExpansionLocation(location, &file, &line, &column, &offset)
 617  	if line == 0 || file == nil {
 618  		// Invalid token.
 619  		return token.NoPos
 620  	}
 621  	filename := getString(C.clang_getFileName(file))
 622  	if _, ok := p.tokenFiles[filename]; !ok {
 623  		// File has not been seen before in this package, add line information
 624  		// now by reading the file from libclang.
 625  		var size C.size_t
 626  		sourcePtr := C.clang_getFileContents(tu, file, &size)
 627  		source := ((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[:size:size]
 628  		lines := []int{0}
 629  		for i := 0; i < len(source)-1; i++ {
 630  			if source[i] == '\n' {
 631  				lines = append(lines, i+1)
 632  			}
 633  		}
 634  		f := p.fset.AddFile(filename, -1, int(size))
 635  		f.SetLines(lines)
 636  		p.tokenFiles[filename] = f
 637  		// Add dummy file AST, to satisfy the type checker.
 638  		astFile := &ast.File{
 639  			Package: f.Pos(0),
 640  			Name:    ast.NewIdent(p.packageName),
 641  		}
 642  		setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
 643  		p.cgoFiles = append(p.cgoFiles, astFile)
 644  	}
 645  	positionFile := p.tokenFiles[filename]
 646  
 647  	// Check for alternative line/column information (set with a line directive).
 648  	var filename2String C.CXString
 649  	var line2 C.unsigned
 650  	var column2 C.unsigned
 651  	C.clang_getPresumedLocation(location, &filename2String, &line2, &column2)
 652  	filename2 := getString(filename2String)
 653  	if filename2 != filename || line2 != line || column2 != column {
 654  		// The location was changed with a preprocessor directive.
 655  		// TODO: this only works for locations that are added in order. Adding
 656  		// line/column info to a file that already has line/column info after
 657  		// the given offset is ignored.
 658  		positionFile.AddLineColumnInfo(int(offset), filename2, int(line2), int(column2))
 659  	}
 660  
 661  	return positionFile.Pos(int(offset))
 662  }
 663  
 664  // addError is a utility function to add an error to the list of errors. It will
 665  // convert the token position to a line/column position first, and call
 666  // addErrorAt.
 667  func (p *cgoPackage) addError(pos token.Pos, msg string) {
 668  	p.addErrorAt(p.fset.PositionFor(pos, true), msg)
 669  }
 670  
 671  // addErrorAfter is like addError, but adds the text `after` to the source
 672  // location.
 673  func (p *cgoPackage) addErrorAfter(pos token.Pos, after, msg string) {
 674  	position := p.fset.PositionFor(pos, true)
 675  	lines := strings.Split(after, "\n")
 676  	if len(lines) != 1 {
 677  		// Adjust lines.
 678  		// For why we can't just do pos+token.Pos(len(after)), see:
 679  		// https://github.com/golang/go/issues/35803
 680  		position.Line += len(lines) - 1
 681  		position.Column = len(lines[len(lines)-1]) + 1
 682  	} else {
 683  		position.Column += len(after)
 684  	}
 685  	p.addErrorAt(position, msg)
 686  }
 687  
 688  // addErrorAt is a utility function to add an error to the list of errors.
 689  func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
 690  	p.errors = append(p.errors, scanner.Error{
 691  		Pos: position,
 692  		Msg: msg,
 693  	})
 694  }
 695  
 696  // makeDecayingASTType does the same as makeASTType but takes care of decaying
 697  // types (arrays in function parameters, etc). It is otherwise identical to
 698  // makeASTType.
 699  func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
 700  	// Strip typedefs, if any.
 701  	underlyingType := typ
 702  	if underlyingType.kind == C.CXType_Elaborated {
 703  		// Starting with LLVM 16, the elaborated type is used for more types.
 704  		// According to the Clang documentation, the elaborated type has no
 705  		// semantic meaning so can be stripped (it is used to better convey type
 706  		// name information).
 707  		// Source:
 708  		// https://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html#details
 709  		// > The type itself is always "sugar", used to express what was written
 710  		// > in the source code but containing no additional semantic information.
 711  		underlyingType = C.clang_Type_getNamedType(underlyingType)
 712  	}
 713  	if underlyingType.kind == C.CXType_Typedef {
 714  		c := C.moxie_clang_getTypeDeclaration(underlyingType)
 715  		underlyingType = C.moxie_clang_getTypedefDeclUnderlyingType(c)
 716  		// TODO: support a chain of typedefs. At the moment, it seems to get
 717  		// stuck in an endless loop when trying to get to the most underlying
 718  		// type.
 719  	}
 720  	// Check for decaying type. An example would be an array type in a
 721  	// parameter. This declaration:
 722  	//   void foo(char buf[6]);
 723  	// is the same as this one:
 724  	//   void foo(char *buf);
 725  	// But this one:
 726  	//   void bar(char buf[6][4]);
 727  	// equals this:
 728  	//   void bar(char *buf[4]);
 729  	// so not all array dimensions should be stripped, just the first one.
 730  	// TODO: there are more kinds of decaying types.
 731  	if underlyingType.kind == C.CXType_ConstantArray {
 732  		// Apply type decaying.
 733  		pointeeType := C.clang_getElementType(underlyingType)
 734  		return &ast.StarExpr{
 735  			Star: pos,
 736  			X:    f.makeASTType(pointeeType, pos),
 737  		}
 738  	}
 739  	return f.makeASTType(typ, pos)
 740  }
 741  
 742  // makeASTType return the ast.Expr for the given libclang type. In other words,
 743  // it converts a libclang type to a type in the Go AST.
 744  func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
 745  	var typeName string
 746  	switch typ.kind {
 747  	case C.CXType_Char_S, C.CXType_Char_U:
 748  		typeName = "_Cgo_char"
 749  	case C.CXType_SChar:
 750  		typeName = "_Cgo_schar"
 751  	case C.CXType_UChar:
 752  		typeName = "_Cgo_uchar"
 753  	case C.CXType_Short:
 754  		typeName = "_Cgo_short"
 755  	case C.CXType_UShort:
 756  		typeName = "_Cgo_ushort"
 757  	case C.CXType_Int:
 758  		typeName = "_Cgo_int"
 759  	case C.CXType_UInt:
 760  		typeName = "_Cgo_uint"
 761  	case C.CXType_Long:
 762  		typeName = "_Cgo_long"
 763  	case C.CXType_ULong:
 764  		typeName = "_Cgo_ulong"
 765  	case C.CXType_LongLong:
 766  		typeName = "_Cgo_longlong"
 767  	case C.CXType_ULongLong:
 768  		typeName = "_Cgo_ulonglong"
 769  	case C.CXType_Bool:
 770  		typeName = "bool"
 771  	case C.CXType_Float, C.CXType_Double, C.CXType_LongDouble:
 772  		switch C.clang_Type_getSizeOf(typ) {
 773  		case 4:
 774  			typeName = "float32"
 775  		case 8:
 776  			typeName = "float64"
 777  		default:
 778  			// Don't do anything, rely on the fallback code to show a somewhat
 779  			// sensible error message like "undeclared name: C.long double".
 780  		}
 781  	case C.CXType_Complex:
 782  		switch C.clang_Type_getSizeOf(typ) {
 783  		case 8:
 784  			typeName = "complex64"
 785  		case 16:
 786  			typeName = "complex128"
 787  		}
 788  	case C.CXType_Pointer:
 789  		pointeeType := C.clang_getPointeeType(typ)
 790  		if pointeeType.kind == C.CXType_Void {
 791  			// void* type is translated to Go as unsafe.Pointer
 792  			return &ast.SelectorExpr{
 793  				X: &ast.Ident{
 794  					NamePos: pos,
 795  					Name:    "unsafe",
 796  				},
 797  				Sel: &ast.Ident{
 798  					NamePos: pos,
 799  					Name:    "Pointer",
 800  				},
 801  			}
 802  		}
 803  		return &ast.StarExpr{
 804  			Star: pos,
 805  			X:    f.makeASTType(pointeeType, pos),
 806  		}
 807  	case C.CXType_ConstantArray:
 808  		return &ast.ArrayType{
 809  			Lbrack: pos,
 810  			Len: &ast.BasicLit{
 811  				ValuePos: pos,
 812  				Kind:     token.INT,
 813  				Value:    strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
 814  			},
 815  			Elt: f.makeASTType(C.clang_getElementType(typ), pos),
 816  		}
 817  	case C.CXType_FunctionProto:
 818  		// Be compatible with gc, which uses the *[0]byte type for function
 819  		// pointer types.
 820  		// Return type [0]byte because this is a function type, not a pointer to
 821  		// this function type.
 822  		return &ast.ArrayType{
 823  			Lbrack: pos,
 824  			Len: &ast.BasicLit{
 825  				ValuePos: pos,
 826  				Kind:     token.INT,
 827  				Value:    "0",
 828  			},
 829  			Elt: &ast.Ident{
 830  				NamePos: pos,
 831  				Name:    "byte",
 832  			},
 833  		}
 834  	case C.CXType_Typedef:
 835  		name := getString(C.clang_getTypedefName(typ))
 836  		c := C.moxie_clang_getTypeDeclaration(typ)
 837  		return &ast.Ident{
 838  			NamePos: pos,
 839  			Name:    f.getASTDeclName(name, c, false),
 840  		}
 841  	case C.CXType_Elaborated:
 842  		underlying := C.clang_Type_getNamedType(typ)
 843  		switch underlying.kind {
 844  		case C.CXType_Record:
 845  			return f.makeASTType(underlying, pos)
 846  		case C.CXType_Enum:
 847  			return f.makeASTType(underlying, pos)
 848  		case C.CXType_Typedef:
 849  			return f.makeASTType(underlying, pos)
 850  		default:
 851  			typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
 852  			f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
 853  			typeName = "<unknown>"
 854  		}
 855  	case C.CXType_Record:
 856  		cursor := C.moxie_clang_getTypeDeclaration(typ)
 857  		name := getString(C.moxie_clang_getCursorSpelling(cursor))
 858  		var cgoRecordPrefix string
 859  		switch C.moxie_clang_getCursorKind(cursor) {
 860  		case C.CXCursor_StructDecl:
 861  			cgoRecordPrefix = "struct_"
 862  		case C.CXCursor_UnionDecl:
 863  			cgoRecordPrefix = "union_"
 864  		default:
 865  			// makeASTRecordType will create an appropriate error.
 866  			cgoRecordPrefix = "record_"
 867  		}
 868  		if name == "" || C.moxie_clang_Cursor_isAnonymous(cursor) != 0 {
 869  			// Anonymous record, probably inside a typedef.
 870  			location := f.getUniqueLocationID(pos, cursor)
 871  			name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
 872  		} else {
 873  			name = cgoRecordPrefix + name
 874  		}
 875  		return &ast.Ident{
 876  			NamePos: pos,
 877  			Name:    f.getASTDeclName(name, cursor, false),
 878  		}
 879  	case C.CXType_Enum:
 880  		cursor := C.moxie_clang_getTypeDeclaration(typ)
 881  		name := getString(C.moxie_clang_getCursorSpelling(cursor))
 882  		if name == "" {
 883  			// Anonymous enum, probably inside a typedef.
 884  			location := f.getUniqueLocationID(pos, cursor)
 885  			name = f.getUnnamedDeclName("_Ctype_enum___", location)
 886  		} else {
 887  			name = "enum_" + name
 888  		}
 889  		return &ast.Ident{
 890  			NamePos: pos,
 891  			Name:    f.getASTDeclName(name, cursor, false),
 892  		}
 893  	}
 894  	if typeName == "" {
 895  		// Report this as an error.
 896  		typeSpelling := getString(C.clang_getTypeSpelling(typ))
 897  		typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
 898  		f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
 899  		typeName = "_Cgo_<unknown>"
 900  	}
 901  	return &ast.Ident{
 902  		NamePos: pos,
 903  		Name:    typeName,
 904  	}
 905  }
 906  
 907  // getIntegerType returns an AST node that defines types such as C.int.
 908  func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSpec {
 909  	pos := p.getCursorPosition(cursor)
 910  
 911  	// Find a Go type that matches the size and signedness of the given C type.
 912  	underlyingType := C.moxie_clang_getTypedefDeclUnderlyingType(cursor)
 913  	var goName string
 914  	typeSize := C.clang_Type_getSizeOf(underlyingType)
 915  	switch name {
 916  	case "_Cgo_char":
 917  		if typeSize != 1 {
 918  			// This happens for some very special purpose architectures
 919  			// (DSPs etc.) that are not currently targeted.
 920  			// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
 921  			p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
 922  		}
 923  		switch underlyingType.kind {
 924  		case C.CXType_Char_S:
 925  			goName = "int8"
 926  		case C.CXType_Char_U:
 927  			goName = "uint8"
 928  		}
 929  	case "_Cgo_schar", "_Cgo_short", "_Cgo_int", "_Cgo_long", "_Cgo_longlong":
 930  		switch typeSize {
 931  		case 1:
 932  			goName = "int8"
 933  		case 2:
 934  			goName = "int16"
 935  		case 4:
 936  			goName = "int32"
 937  		case 8:
 938  			goName = "int64"
 939  		}
 940  	case "_Cgo_uchar", "_Cgo_ushort", "_Cgo_uint", "_Cgo_ulong", "_Cgo_ulonglong":
 941  		switch typeSize {
 942  		case 1:
 943  			goName = "uint8"
 944  		case 2:
 945  			goName = "uint16"
 946  		case 4:
 947  			goName = "uint32"
 948  		case 8:
 949  			goName = "uint64"
 950  		}
 951  	}
 952  
 953  	if goName == "" { // should not happen
 954  		p.addError(pos, "internal error: did not find Go type for C type "+name)
 955  		goName = "int"
 956  	}
 957  
 958  	// Construct an *ast.TypeSpec for this type.
 959  	obj := &ast.Object{
 960  		Kind: ast.Typ,
 961  		Name: name,
 962  	}
 963  	spec := &ast.TypeSpec{
 964  		Name: &ast.Ident{
 965  			NamePos: pos,
 966  			Name:    name,
 967  			Obj:     obj,
 968  		},
 969  		Type: &ast.Ident{
 970  			NamePos: pos,
 971  			Name:    goName,
 972  		},
 973  	}
 974  	obj.Decl = spec
 975  	return spec
 976  }
 977  
 978  // makeASTRecordType parses a C record (struct or union) and translates it into
 979  // a Go struct type.
 980  func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
 981  	fieldList := &ast.FieldList{
 982  		Opening: pos,
 983  		Closing: pos,
 984  	}
 985  	var bitfieldList []bitfieldInfo
 986  	inBitfield := false
 987  	bitfieldNum := 0
 988  	ref := storedRefs.Put(struct {
 989  		fieldList    *ast.FieldList
 990  		file         *cgoFile
 991  		inBitfield   *bool
 992  		bitfieldNum  *int
 993  		bitfieldList *[]bitfieldInfo
 994  	}{fieldList, f, &inBitfield, &bitfieldNum, &bitfieldList})
 995  	defer storedRefs.Remove(ref)
 996  	C.moxie_clang_visitChildren(cursor, C.CXCursorVisitor(C.moxie_clang_struct_visitor), C.CXClientData(ref))
 997  	renameFieldKeywords(fieldList)
 998  	switch C.moxie_clang_getCursorKind(cursor) {
 999  	case C.CXCursor_StructDecl:
1000  		return &elaboratedTypeInfo{
1001  			typeExpr: &ast.StructType{
1002  				Struct: pos,
1003  				Fields: fieldList,
1004  			},
1005  			pos:       pos,
1006  			bitfields: bitfieldList,
1007  		}
1008  	case C.CXCursor_UnionDecl:
1009  		typeInfo := &elaboratedTypeInfo{
1010  			typeExpr: &ast.StructType{
1011  				Struct: pos,
1012  				Fields: fieldList,
1013  			},
1014  			pos:       pos,
1015  			bitfields: bitfieldList,
1016  		}
1017  		if len(fieldList.List) <= 1 {
1018  			// Useless union, treat it as a regular struct.
1019  			return typeInfo
1020  		}
1021  		if bitfieldList != nil {
1022  			// This is valid C... but please don't do this.
1023  			f.addError(pos, "bitfield in a union is not supported")
1024  		}
1025  		typ := C.moxie_clang_getCursorType(cursor)
1026  		alignInBytes := int64(C.clang_Type_getAlignOf(typ))
1027  		sizeInBytes := int64(C.clang_Type_getSizeOf(typ))
1028  		if sizeInBytes == 0 {
1029  			f.addError(pos, "zero-length union is not supported")
1030  		}
1031  		typeInfo.unionSize = sizeInBytes
1032  		typeInfo.unionAlign = alignInBytes
1033  		return typeInfo
1034  	default:
1035  		cursorKind := C.moxie_clang_getCursorKind(cursor)
1036  		cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
1037  		f.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
1038  		return &elaboratedTypeInfo{
1039  			typeExpr: &ast.StructType{
1040  				Struct: pos,
1041  			},
1042  			pos: pos,
1043  		}
1044  	}
1045  }
1046  
1047  //export moxie_clang_struct_visitor
1048  func moxie_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
1049  	passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
1050  		fieldList    *ast.FieldList
1051  		file         *cgoFile
1052  		inBitfield   *bool
1053  		bitfieldNum  *int
1054  		bitfieldList *[]bitfieldInfo
1055  	})
1056  	fieldList := passed.fieldList
1057  	f := passed.file
1058  	inBitfield := passed.inBitfield
1059  	bitfieldNum := passed.bitfieldNum
1060  	bitfieldList := passed.bitfieldList
1061  	pos := f.getCursorPosition(c)
1062  	switch cursorKind := C.moxie_clang_getCursorKind(c); cursorKind {
1063  	case C.CXCursor_FieldDecl:
1064  		// Expected. This is a regular field.
1065  	case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
1066  		// Ignore. The next field will be the struct/union itself.
1067  		return C.CXChildVisit_Continue
1068  	default:
1069  		cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
1070  		f.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
1071  		return C.CXChildVisit_Continue
1072  	}
1073  	name := getString(C.moxie_clang_getCursorSpelling(c))
1074  	if name == "" {
1075  		// Assume this is a bitfield of 0 bits.
1076  		// Warning: this is not necessarily true!
1077  		return C.CXChildVisit_Continue
1078  	}
1079  	typ := C.moxie_clang_getCursorType(c)
1080  	field := &ast.Field{
1081  		Type: f.makeASTType(typ, f.getCursorPosition(c)),
1082  	}
1083  	offsetof := int64(C.clang_Type_getOffsetOf(C.moxie_clang_getCursorType(parent), C.CString(name)))
1084  	alignOf := int64(C.clang_Type_getAlignOf(typ) * 8)
1085  	bitfieldOffset := offsetof % alignOf
1086  	if bitfieldOffset != 0 {
1087  		if C.moxie_clang_Cursor_isBitField(c) != 1 {
1088  			f.addError(pos, "expected a bitfield")
1089  			return C.CXChildVisit_Continue
1090  		}
1091  		if !*inBitfield {
1092  			*bitfieldNum++
1093  		}
1094  		bitfieldName := "__bitfield_" + strconv.Itoa(*bitfieldNum)
1095  		prevField := fieldList.List[len(fieldList.List)-1]
1096  		if !*inBitfield {
1097  			// The previous element also was a bitfield, but wasn't noticed
1098  			// then. Add it now.
1099  			*inBitfield = true
1100  			*bitfieldList = append(*bitfieldList, bitfieldInfo{
1101  				field:    prevField,
1102  				name:     prevField.Names[0].Name,
1103  				startBit: 0,
1104  				pos:      prevField.Names[0].NamePos,
1105  			})
1106  			prevField.Names[0].Name = bitfieldName
1107  			prevField.Names[0].Obj.Name = bitfieldName
1108  		}
1109  		prevBitfield := &(*bitfieldList)[len(*bitfieldList)-1]
1110  		prevBitfield.endBit = bitfieldOffset
1111  		*bitfieldList = append(*bitfieldList, bitfieldInfo{
1112  			field:    prevField,
1113  			name:     name,
1114  			startBit: bitfieldOffset,
1115  			pos:      pos,
1116  		})
1117  		return C.CXChildVisit_Continue
1118  	}
1119  	*inBitfield = false
1120  	field.Names = []*ast.Ident{
1121  		{
1122  			NamePos: pos,
1123  			Name:    name,
1124  			Obj: &ast.Object{
1125  				Kind: ast.Var,
1126  				Name: name,
1127  				Decl: field,
1128  			},
1129  		},
1130  	}
1131  	fieldList.List = append(fieldList.List, field)
1132  	return C.CXChildVisit_Continue
1133  }
1134  
1135  //export moxie_clang_inclusion_visitor
1136  func moxie_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) {
1137  	callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile))
1138  	callback(includedFile)
1139  }
1140