diff --git a/cgo/libclang.go b/cgo/libclang.go index 3c0d196df..27ac1b576 100644 --- a/cgo/libclang.go +++ b/cgo/libclang.go @@ -533,6 +533,26 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient return C.CXChildVisit_Continue } +// Get the precise location in the source code. Used for uniquely identifying +// source locations. +func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) interface{} { + clangLocation := C.tinygo_clang_getCursorLocation(cursor) + var file C.CXFile + var line C.unsigned + var column C.unsigned + C.clang_getFileLocation(clangLocation, &file, &line, &column, nil) + location := token.Position{ + Filename: getString(C.clang_getFileName(file)), + Line: int(line), + Column: int(column), + } + if location.Filename == "" || location.Line == 0 { + // Not sure when this would happen, but protect from it anyway. + f.addError(pos, "could not find file/line information") + } + return location +} + // getCursorPosition returns a usable token.Pos from a libclang cursor. func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos { return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor)) @@ -788,20 +808,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr { } if name == "" { // Anonymous record, probably inside a typedef. - clangLocation := C.tinygo_clang_getCursorLocation(cursor) - var file C.CXFile - var line C.unsigned - var column C.unsigned - C.clang_getFileLocation(clangLocation, &file, &line, &column, nil) - location := token.Position{ - Filename: getString(C.clang_getFileName(file)), - Line: int(line), - Column: int(column), - } - if location.Filename == "" || location.Line == 0 { - // Not sure when this would happen, but protect from it anyway. - f.addError(pos, "could not find file/line information") - } + location := f.getUniqueLocationID(pos, cursor) name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location) } else { name = cgoRecordPrefix + name @@ -814,7 +821,9 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr { cursor := C.tinygo_clang_getTypeDeclaration(typ) name := getString(C.tinygo_clang_getCursorSpelling(cursor)) if name == "" { - name = f.getUnnamedDeclName("_Ctype_enum___", cursor) + // Anonymous enum, probably inside a typedef. + location := f.getUniqueLocationID(pos, cursor) + name = f.getUnnamedDeclName("_Ctype_enum___", location) } else { name = "enum_" + name } diff --git a/testdata/cgo/extra.go b/testdata/cgo/extra.go index f8ce946db..401733ba9 100644 --- a/testdata/cgo/extra.go +++ b/testdata/cgo/extra.go @@ -2,6 +2,7 @@ package main // Make sure CGo supports multiple files. +// #include "test.h" // int fortytwo(void); // static float headerfunc_static(float a) { return a - 1; } // static void headerfunc_void(int a, int *ptr) { *ptr = a; } @@ -17,4 +18,8 @@ func headerfunc_2() { var n C.int C.headerfunc_void(3, &n) println("static headerfunc void:", n) + + // anonymous structs and enums in multiple Go files + var _ C.teststruct + var _ C.testenum } diff --git a/testdata/cgo/main.go b/testdata/cgo/main.go index f4ee532a8..4555c922f 100644 --- a/testdata/cgo/main.go +++ b/testdata/cgo/main.go @@ -4,6 +4,7 @@ package main #include int fortytwo(void); #include "main.h" +#include "test.h" int mul(int, int); #include #cgo CFLAGS: -DSOME_CONSTANT=17 @@ -128,6 +129,10 @@ func main() { println("option 2A:", C.option2A) println("option 3A:", C.option3A) + // anonymous structs and enums in multiple Go files + var _ C.teststruct + var _ C.testenum + // Check that enums are considered the same width in C and CGo. println("enum width matches:", unsafe.Sizeof(C.option2_t(0)) == uintptr(C.smallEnumWidth)) diff --git a/testdata/cgo/test.h b/testdata/cgo/test.h new file mode 100644 index 000000000..8b5b32ea8 --- /dev/null +++ b/testdata/cgo/test.h @@ -0,0 +1,11 @@ +#pragma once + +typedef struct { + int a; + int b; +} teststruct; + +typedef enum { + v0, + v1 +} testenum;