aboutsummaryrefslogtreecommitdiffhomepage
path: root/cgo
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2022-11-27 14:18:22 +0100
committerRon Evans <[email protected]>2023-09-18 21:58:02 +0200
commit1d7543e2bfcba3eed51f5340dcaf607d11b0bdeb (patch)
tree2125653ea6b465f39b05a9d76af9282c255959d2 /cgo
parentff32fbbb4ff266f5f29080479a29d941cad2a57e (diff)
downloadtinygo-1d7543e2bfcba3eed51f5340dcaf607d11b0bdeb.tar.gz
tinygo-1d7543e2bfcba3eed51f5340dcaf607d11b0bdeb.zip
all: switch to LLVM 16
This commit adds support for LLVM 16 and switches to it by default. That means three LLVM versions are supported at the same time: LLVM 14, 15, and 16. This commit includes work by QuLogic: * Part of this work was based on a PR by QuLogic: https://github.com/tinygo-org/tinygo/pull/3649 But I also had parts of this already implemented in an old branch I already made for LLVM 16. * QuLogic also provided a CGo fix here, which is also incorporated in this commit: https://github.com/tinygo-org/tinygo/pull/3869 The difference with the original PR by QuLogic is that this commit is more complete: * It switches to LLVM 16 by default. * It updates some things to also make it work with a self-built LLVM. * It fixes the CGo bug in a slightly different way, and also fixes another one not included in the original PR. * It does not keep compiler tests passing on older LLVM versions. I have found this to be quite burdensome and therefore don't generally do this - the smoke tests should hopefully catch most regressions.
Diffstat (limited to 'cgo')
-rw-r--r--cgo/libclang.go18
-rw-r--r--cgo/libclang_config_llvm15.go2
-rw-r--r--cgo/libclang_config_llvm16.go21
-rw-r--r--cgo/libclang_stubs.c6
-rw-r--r--cgo/testdata/errors.out.go4
-rw-r--r--cgo/testdata/types.out.go70
6 files changed, 79 insertions, 42 deletions
diff --git a/cgo/libclang.go b/cgo/libclang.go
index 27ac1b576..1f2922c56 100644
--- a/cgo/libclang.go
+++ b/cgo/libclang.go
@@ -60,6 +60,7 @@ CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
+unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c);
unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c);
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
@@ -653,8 +654,19 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
// Strip typedefs, if any.
underlyingType := typ
+ if underlyingType.kind == C.CXType_Elaborated {
+ // Starting with LLVM 16, the elaborated type is used for more types.
+ // According to the Clang documentation, the elaborated type has no
+ // semantic meaning so can be stripped (it is used to better convey type
+ // name information).
+ // Source:
+ // https://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html#details
+ // > The type itself is always "sugar", used to express what was written
+ // > in the source code but containing no additional semantic information.
+ underlyingType = C.clang_Type_getNamedType(underlyingType)
+ }
if underlyingType.kind == C.CXType_Typedef {
- c := C.tinygo_clang_getTypeDeclaration(typ)
+ c := C.tinygo_clang_getTypeDeclaration(underlyingType)
underlyingType = C.tinygo_clang_getTypedefDeclUnderlyingType(c)
// TODO: support a chain of typedefs. At the moment, it seems to get
// stuck in an endless loop when trying to get to the most underlying
@@ -788,6 +800,8 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
return f.makeASTType(underlying, pos)
case C.CXType_Enum:
return f.makeASTType(underlying, pos)
+ case C.CXType_Typedef:
+ return f.makeASTType(underlying, pos)
default:
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
@@ -806,7 +820,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
// makeASTRecordType will create an appropriate error.
cgoRecordPrefix = "record_"
}
- if name == "" {
+ if name == "" || C.tinygo_clang_Cursor_isAnonymous(cursor) != 0 {
// Anonymous record, probably inside a typedef.
location := f.getUniqueLocationID(pos, cursor)
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
diff --git a/cgo/libclang_config_llvm15.go b/cgo/libclang_config_llvm15.go
index 32daf0608..e105dfe72 100644
--- a/cgo/libclang_config_llvm15.go
+++ b/cgo/libclang_config_llvm15.go
@@ -1,4 +1,4 @@
-//go:build !byollvm && !llvm14
+//go:build !byollvm && llvm15
package cgo
diff --git a/cgo/libclang_config_llvm16.go b/cgo/libclang_config_llvm16.go
new file mode 100644
index 000000000..79aacd2f2
--- /dev/null
+++ b/cgo/libclang_config_llvm16.go
@@ -0,0 +1,21 @@
+//go:build !byollvm && !llvm14 && !llvm15
+
+package cgo
+
+// As of 2023-05-05, there is a packaging issue on Debian:
+// https://github.com/llvm/llvm-project/issues/62199
+// A workaround is to fix this locally, using something like this:
+//
+// ln -sf ../../x86_64-linux-gnu/libclang-16.so.1 /usr/lib/llvm-16/lib/libclang.so
+
+/*
+#cgo linux CFLAGS: -I/usr/lib/llvm-16/include
+#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@16/include
+#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
+#cgo freebsd CFLAGS: -I/usr/local/llvm16/include
+#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
+#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang -lffi
+#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang -lffi
+#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
+*/
+import "C"
diff --git a/cgo/libclang_stubs.c b/cgo/libclang_stubs.c
index b0668ed71..1b157d0aa 100644
--- a/cgo/libclang_stubs.c
+++ b/cgo/libclang_stubs.c
@@ -77,6 +77,10 @@ CXType tinygo_clang_getEnumDeclIntegerType(CXCursor c) {
return clang_getEnumDeclIntegerType(c);
}
+unsigned tinygo_clang_Cursor_isAnonymous(CXCursor c) {
+ return clang_Cursor_isAnonymous(c);
+}
+
unsigned tinygo_clang_Cursor_isBitField(CXCursor c) {
return clang_Cursor_isBitField(c);
-} \ No newline at end of file
+}
diff --git a/cgo/testdata/errors.out.go b/cgo/testdata/errors.out.go
index 716fd771b..b1646a2e0 100644
--- a/cgo/testdata/errors.out.go
+++ b/cgo/testdata/errors.out.go
@@ -51,10 +51,10 @@ type (
C.longlong int64
C.ulonglong uint64
)
-type C._Ctype_struct___0 struct {
+type C.struct_point_t struct {
x C.int
y C.int
}
-type C.point_t = C._Ctype_struct___0
+type C.point_t = C.struct_point_t
const C.SOME_CONST_3 = 1234
diff --git a/cgo/testdata/types.out.go b/cgo/testdata/types.out.go
index bd7b3fc42..a35d3733c 100644
--- a/cgo/testdata/types.out.go
+++ b/cgo/testdata/types.out.go
@@ -38,11 +38,11 @@ type (
C.ulonglong uint64
)
type C.myint = C.int
-type C._Ctype_struct___0 struct {
+type C.struct_point2d_t struct {
x C.int
y C.int
}
-type C.point2d_t = C._Ctype_struct___0
+type C.point2d_t = C.struct_point2d_t
type C.struct_point3d struct {
x C.int
y C.int
@@ -55,21 +55,19 @@ type C.struct_type1 struct {
___type C.int
}
type C.struct_type2 struct{ _type C.int }
-type C._Ctype_union___1 struct{ i C.int }
-type C.union1_t = C._Ctype_union___1
-type C._Ctype_union___2 struct{ $union uint64 }
+type C.union_union1_t struct{ i C.int }
+type C.union1_t = C.union_union1_t
+type C.union_union3_t struct{ $union uint64 }
-func (union *C._Ctype_union___2) unionfield_i() *C.int {
- return (*C.int)(unsafe.Pointer(&union.$union))
-}
-func (union *C._Ctype_union___2) unionfield_d() *float64 {
+func (union *C.union_union3_t) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
+func (union *C.union_union3_t) unionfield_d() *float64 {
return (*float64)(unsafe.Pointer(&union.$union))
}
-func (union *C._Ctype_union___2) unionfield_s() *C.short {
+func (union *C.union_union3_t) unionfield_s() *C.short {
return (*C.short)(unsafe.Pointer(&union.$union))
}
-type C.union3_t = C._Ctype_union___2
+type C.union3_t = C.union_union3_t
type C.union_union2d struct{ $union [2]uint64 }
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
@@ -78,50 +76,50 @@ func (union *C.union_union2d) unionfield_d() *[2]float64 {
}
type C.union2d_t = C.union_union2d
-type C._Ctype_union___3 struct{ arr [10]C.uchar }
-type C.unionarray_t = C._Ctype_union___3
-type C._Ctype_union___5 struct{ $union [3]uint32 }
+type C.union_unionarray_t struct{ arr [10]C.uchar }
+type C.unionarray_t = C.union_unionarray_t
+type C._Ctype_union___0 struct{ $union [3]uint32 }
-func (union *C._Ctype_union___5) unionfield_area() *C.point2d_t {
+func (union *C._Ctype_union___0) unionfield_area() *C.point2d_t {
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
}
-func (union *C._Ctype_union___5) unionfield_solid() *C.point3d_t {
+func (union *C._Ctype_union___0) unionfield_solid() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
-type C._Ctype_struct___4 struct {
+type C.struct_struct_nested_t struct {
begin C.point2d_t
end C.point2d_t
tag C.int
- coord C._Ctype_union___5
+ coord C._Ctype_union___0
}
-type C.struct_nested_t = C._Ctype_struct___4
-type C._Ctype_union___6 struct{ $union [2]uint64 }
+type C.struct_nested_t = C.struct_struct_nested_t
+type C.union_union_nested_t struct{ $union [2]uint64 }
-func (union *C._Ctype_union___6) unionfield_point() *C.point3d_t {
+func (union *C.union_union_nested_t) unionfield_point() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
-func (union *C._Ctype_union___6) unionfield_array() *C.unionarray_t {
+func (union *C.union_union_nested_t) unionfield_array() *C.unionarray_t {
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
}
-func (union *C._Ctype_union___6) unionfield_thing() *C.union3_t {
+func (union *C.union_union_nested_t) unionfield_thing() *C.union3_t {
return (*C.union3_t)(unsafe.Pointer(&union.$union))
}
-type C.union_nested_t = C._Ctype_union___6
+type C.union_nested_t = C.union_union_nested_t
type C.enum_option = C.int
type C.option_t = C.enum_option
-type C._Ctype_enum___7 = C.uint
-type C.option2_t = C._Ctype_enum___7
-type C._Ctype_struct___8 struct {
+type C.enum_option2_t = C.uint
+type C.option2_t = C.enum_option2_t
+type C.struct_types_t struct {
f float32
d float64
ptr *C.int
}
-type C.types_t = C._Ctype_struct___8
+type C.types_t = C.struct_types_t
type C.myIntArray = [10]C.int
-type C._Ctype_struct___9 struct {
+type C.struct_bitfield_t struct {
start C.uchar
__bitfield_1 C.uchar
@@ -129,21 +127,21 @@ type C._Ctype_struct___9 struct {
e C.uchar
}
-func (s *C._Ctype_struct___9) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
-func (s *C._Ctype_struct___9) set_bitfield_a(value C.uchar) {
+func (s *C.struct_bitfield_t) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
+func (s *C.struct_bitfield_t) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
}
-func (s *C._Ctype_struct___9) bitfield_b() C.uchar {
+func (s *C.struct_bitfield_t) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1
}
-func (s *C._Ctype_struct___9) set_bitfield_b(value C.uchar) {
+func (s *C.struct_bitfield_t) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
}
-func (s *C._Ctype_struct___9) bitfield_c() C.uchar {
+func (s *C.struct_bitfield_t) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6
}
-func (s *C._Ctype_struct___9) set_bitfield_c(value C.uchar,
+func (s *C.struct_bitfield_t) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
-type C.bitfield_t = C._Ctype_struct___9
+type C.bitfield_t = C.struct_bitfield_t