cgo: support anonymous enums included in multiple Go files

Anonymous enums (often used in typedefs) triggered a problem that was
already solved for structs but wasn't yet solved for enums. So this
patch generalizes the code to work for both structs and enums, and adds
testing for both.
Этот коммит содержится в:
Ayke van Laethem 2022-10-30 21:12:57 +01:00 коммит произвёл Ron Evans
родитель bce0516394
коммит aaa860f154
4 изменённых файлов: 45 добавлений и 15 удалений

Просмотреть файл

@ -533,6 +533,26 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
return C.CXChildVisit_Continue 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. // getCursorPosition returns a usable token.Pos from a libclang cursor.
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos { func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor)) 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 == "" { if name == "" {
// Anonymous record, probably inside a typedef. // Anonymous record, probably inside a typedef.
clangLocation := C.tinygo_clang_getCursorLocation(cursor) location := f.getUniqueLocationID(pos, 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")
}
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location) name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
} else { } else {
name = cgoRecordPrefix + name 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) cursor := C.tinygo_clang_getTypeDeclaration(typ)
name := getString(C.tinygo_clang_getCursorSpelling(cursor)) name := getString(C.tinygo_clang_getCursorSpelling(cursor))
if name == "" { 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 { } else {
name = "enum_" + name name = "enum_" + name
} }

5
testdata/cgo/extra.go предоставленный
Просмотреть файл

@ -2,6 +2,7 @@ package main
// Make sure CGo supports multiple files. // Make sure CGo supports multiple files.
// #include "test.h"
// int fortytwo(void); // int fortytwo(void);
// static float headerfunc_static(float a) { return a - 1; } // static float headerfunc_static(float a) { return a - 1; }
// static void headerfunc_void(int a, int *ptr) { *ptr = a; } // static void headerfunc_void(int a, int *ptr) { *ptr = a; }
@ -17,4 +18,8 @@ func headerfunc_2() {
var n C.int var n C.int
C.headerfunc_void(3, &n) C.headerfunc_void(3, &n)
println("static headerfunc void:", n) println("static headerfunc void:", n)
// anonymous structs and enums in multiple Go files
var _ C.teststruct
var _ C.testenum
} }

5
testdata/cgo/main.go предоставленный
Просмотреть файл

@ -4,6 +4,7 @@ package main
#include <stdio.h> #include <stdio.h>
int fortytwo(void); int fortytwo(void);
#include "main.h" #include "main.h"
#include "test.h"
int mul(int, int); int mul(int, int);
#include <string.h> #include <string.h>
#cgo CFLAGS: -DSOME_CONSTANT=17 #cgo CFLAGS: -DSOME_CONSTANT=17
@ -128,6 +129,10 @@ func main() {
println("option 2A:", C.option2A) println("option 2A:", C.option2A)
println("option 3A:", C.option3A) 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. // 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)) println("enum width matches:", unsafe.Sizeof(C.option2_t(0)) == uintptr(C.smallEnumWidth))

11
testdata/cgo/test.h предоставленный Обычный файл
Просмотреть файл

@ -0,0 +1,11 @@
#pragma once
typedef struct {
int a;
int b;
} teststruct;
typedef enum {
v0,
v1
} testenum;