aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r--libgo/go/cmd/cgo/ast.go104
-rw-r--r--libgo/go/cmd/cgo/doc.go149
-rw-r--r--libgo/go/cmd/cgo/gcc.go354
-rw-r--r--libgo/go/cmd/cgo/godefs.go3
-rw-r--r--libgo/go/cmd/cgo/main.go80
-rw-r--r--libgo/go/cmd/cgo/out.go248
6 files changed, 725 insertions, 213 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 8bbd1cc..c3a24c2 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -124,7 +124,7 @@ func (f *File) ReadGo(name string) {
if f.Ref == nil {
f.Ref = make([]*Ref, 0, 8)
}
- f.walk(ast2, "prog", (*File).saveRef)
+ f.walk(ast2, "prog", (*File).saveExprs)
// Accumulate exported functions.
// The comments are only on ast1 but we need to
@@ -163,52 +163,72 @@ func commentText(g *ast.CommentGroup) string {
return strings.Join(pieces, "")
}
+// Save various references we are going to need later.
+func (f *File) saveExprs(x interface{}, context string) {
+ switch x := x.(type) {
+ case *ast.Expr:
+ switch (*x).(type) {
+ case *ast.SelectorExpr:
+ f.saveRef(x, context)
+ }
+ case *ast.CallExpr:
+ f.saveCall(x)
+ }
+}
+
// Save references to C.xxx for later processing.
-func (f *File) saveRef(x interface{}, context string) {
- n, ok := x.(*ast.Expr)
- if !ok {
+func (f *File) saveRef(n *ast.Expr, context string) {
+ sel := (*n).(*ast.SelectorExpr)
+ // For now, assume that the only instance of capital C is when
+ // used as the imported package identifier.
+ // The parser should take care of scoping in the future, so
+ // that we will be able to distinguish a "top-level C" from a
+ // local C.
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
return
}
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
- if context == "as2" {
- context = "expr"
- }
- if context == "embed-type" {
- error_(sel.Pos(), "cannot embed C type")
- }
- goname := sel.Sel.Name
- if goname == "errno" {
- error_(sel.Pos(), "cannot refer to errno directly; see documentation")
- return
- }
- if goname == "_CMalloc" {
- error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
- return
- }
- if goname == "malloc" {
- goname = "_CMalloc"
- }
- name := f.Name[goname]
- if name == nil {
- name = &Name{
- Go: goname,
- }
- f.Name[goname] = name
- }
- f.Ref = append(f.Ref, &Ref{
- Name: name,
- Expr: n,
- Context: context,
- })
- return
+ if context == "as2" {
+ context = "expr"
+ }
+ if context == "embed-type" {
+ error_(sel.Pos(), "cannot embed C type")
+ }
+ goname := sel.Sel.Name
+ if goname == "errno" {
+ error_(sel.Pos(), "cannot refer to errno directly; see documentation")
+ return
+ }
+ if goname == "_CMalloc" {
+ error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
+ return
+ }
+ if goname == "malloc" {
+ goname = "_CMalloc"
+ }
+ name := f.Name[goname]
+ if name == nil {
+ name = &Name{
+ Go: goname,
}
+ f.Name[goname] = name
+ }
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+}
+
+// Save calls to C.xxx for later processing.
+func (f *File) saveCall(call *ast.CallExpr) {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+ return
}
+ f.Calls = append(f.Calls, call)
}
// If a function should be exported add it to ExpFunc.
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index b2a5428..bd38a5c 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -117,17 +117,27 @@ The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long),
-C.ulonglong (unsigned long long), C.float, C.double.
+C.ulonglong (unsigned long long), C.float, C.double,
+C.complexfloat (complex float), and C.complexdouble (complex double).
The C type void* is represented by Go's unsafe.Pointer.
+The C types __int128_t and __uint128_t are represented by [16]byte.
To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat.
+The size of any C type T is available as C.sizeof_T, as in
+C.sizeof_struct_stat.
+
As Go doesn't have support for C's union type in the general case,
C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
+Go code can not refer to zero-sized fields that occur at the end of
+non-empty C structs. To get the address of such a field (which is the
+only operation you can do with a zero-sized field) you must take the
+address of the struct and add the size of the struct.
+
Cgo translates C types into equivalent unexported Go types.
Because the translations are unexported, a Go package should not
expose C types in its exported API: a C type used in one Go package
@@ -188,10 +198,10 @@ by making copies of the data. In pseudo-Go definitions:
// C string to Go string
func C.GoString(*C.char) string
- // C string, length to Go string
+ // C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string
- // C pointer, length to Go []byte
+ // C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
C references to Go
@@ -221,6 +231,55 @@ definitions and declarations, then the two output files will produce
duplicate symbols and the linker will fail. To avoid this, definitions
must be placed in preambles in other files, or in C source files.
+Passing pointers
+
+Go is a garbage collected language, and the garbage collector needs to
+know the location of every pointer to Go memory. Because of this,
+there are restrictions on passing pointers between Go and C.
+
+In this section the term Go pointer means a pointer to memory
+allocated by Go (such as by using the & operator or calling the
+predefined new function) and the term C pointer means a pointer to
+memory allocated by C (such as by a call to C.malloc). Whether a
+pointer is a Go pointer or a C pointer is a dynamic property
+determined by how the memory was allocated; it has nothing to do with
+the type of the pointer.
+
+Go code may pass a Go pointer to C provided the Go memory to which it
+points does not contain any Go pointers. The C code must preserve
+this property: it must not store any Go pointers in Go memory, even
+temporarily. When passing a pointer to a field in a struct, the Go
+memory in question is the memory occupied by the field, not the entire
+struct. When passing a pointer to an element in an array or slice,
+the Go memory in question is the entire array or the entire backing
+array of the slice.
+
+C code may not keep a copy of a Go pointer after the call returns.
+
+A Go function called by C code may not return a Go pointer. A Go
+function called by C code may take C pointers as arguments, and it may
+store non-pointer or C pointer data through those pointers, but it may
+not store a Go pointer in memory pointed to by a C pointer. A Go
+function called by C code may take a Go pointer as an argument, but it
+must preserve the property that the Go memory to which it points does
+not contain any Go pointers.
+
+Go code may not store a Go pointer in C memory. C code may store Go
+pointers in C memory, subject to the rule above: it must stop storing
+the Go pointer when the C function returns.
+
+These rules are checked dynamically at runtime. The checking is
+controlled by the cgocheck setting of the GODEBUG environment
+variable. The default setting is GODEBUG=cgocheck=1, which implements
+reasonably cheap dynamic checks. These checks may be disabled
+entirely using GODEBUG=cgocheck=0. Complete checking of pointer
+handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
+
+It is possible to defeat this enforcement by using the unsafe package,
+and of course there is nothing stopping the C code from doing anything
+it likes. However, programs that break these rules are likely to fail
+in unexpected and unpredictable ways.
+
Using cgo directly
Usage:
@@ -391,17 +450,13 @@ the translation process.
Translating Go
-[The rest of this comment refers to 6g, the Go compiler that is part
-of the amd64 port of the gc Go toolchain. Everything here applies to
-another architecture's compilers as well.]
-
Given the input Go files x.go and y.go, cgo generates these source
files:
- x.cgo1.go # for 6g
- y.cgo1.go # for 6g
- _cgo_gotypes.go # for 6g
- _cgo_import.go # for 6g (if -dynout _cgo_import.go)
+ x.cgo1.go # for gc (cmd/compile)
+ y.cgo1.go # for gc
+ _cgo_gotypes.go # for gc
+ _cgo_import.go # for gc (if -dynout _cgo_import.go)
x.cgo2.c # for gcc
y.cgo2.c # for gcc
_cgo_defun.c # for gcc (if -gccgo)
@@ -464,7 +519,7 @@ Linking
Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
they need to be linked into the final binary, along with the libraries
-they might depend on (in the case of puts, stdio). 6l has been
+they might depend on (in the case of puts, stdio). cmd/link has been
extended to understand basic ELF files, but it does not understand ELF
in the full complexity that modern C libraries embrace, so it cannot
in general generate direct references to the system libraries.
@@ -495,23 +550,23 @@ _cgo_import.go, which looks like:
//go:cgo_import_dynamic _ _ "libc.so.6"
In the end, the compiled Go package, which will eventually be
-presented to 6l as part of a larger program, contains:
+presented to cmd/link as part of a larger program, contains:
- _go_.6 # 6g-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
+ _go_.o # gc-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
_all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c
-The final program will be a dynamic executable, so that 6l can avoid
+The final program will be a dynamic executable, so that cmd/link can avoid
needing to process arbitrary .o files. It only needs to process the .o
files generated from C files that cgo writes, and those are much more
limited in the ELF or other features that they use.
-In essence, the _cgo_import.6 file includes the extra linking
-directives that 6l is not sophisticated enough to derive from _all.o
+In essence, the _cgo_import.o file includes the extra linking
+directives that cmd/link is not sophisticated enough to derive from _all.o
on its own. Similarly, the _all.o uses dynamic references to real
-system object code because 6l is not sophisticated enough to process
+system object code because cmd/link is not sophisticated enough to process
the real code.
-The main benefits of this system are that 6l remains relatively simple
+The main benefits of this system are that cmd/link remains relatively simple
(it does not need to implement a complete ELF and Mach-O linker) and
that gcc is not needed after the package is compiled. For example,
package net uses cgo for access to name resolution functions provided
@@ -540,17 +595,17 @@ system calls.
Internal and External Linking
-The text above describes "internal" linking, in which 6l parses and
+The text above describes "internal" linking, in which cmd/link parses and
links host object files (ELF, Mach-O, PE, and so on) into the final
-executable itself. Keeping 6l simple means we cannot possibly
+executable itself. Keeping cmd/link simple means we cannot possibly
implement the full semantics of the host linker, so the kinds of
objects that can be linked directly into the binary is limited (other
code can only be used as a dynamic library). On the other hand, when
-using internal linking, 6l can generate Go binaries by itself.
+using internal linking, cmd/link can generate Go binaries by itself.
In order to allow linking arbitrary object files without requiring
dynamic libraries, cgo supports an "external" linking mode too. In
-external linking mode, 6l does not process any host object files.
+external linking mode, cmd/link does not process any host object files.
Instead, it collects all the Go code and writes a single go.o object
file containing it. Then it invokes the host linker (usually gcc) to
combine the go.o object file and any supporting non-Go code into a
@@ -582,8 +637,8 @@ to be made when linking the final binary.
Linking Directives
In either linking mode, package-specific directives must be passed
-through to 6l. These are communicated by writing //go: directives in a
-Go source file compiled by 6g. The directives are copied into the .6
+through to cmd/link. These are communicated by writing //go: directives in a
+Go source file compiled by gc. The directives are copied into the .o
object file and then processed by the linker.
The directives are:
@@ -672,7 +727,7 @@ Example
As a simple example, consider a package that uses cgo to call C.sin.
The following code will be generated by cgo:
- // compiled by 6g
+ // compiled by gc
//go:cgo_ldflag "-lm"
@@ -708,7 +763,7 @@ Otherwise the link will be an internal one.
The linking directives are used according to the kind of final link
used.
-In internal mode, 6l itself processes all the host object files, in
+In internal mode, cmd/link itself processes all the host object files, in
particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
cgo_dynamic_linker directives to learn that the otherwise undefined
reference to sin in foo.cgo2.o should be rewritten to refer to the
@@ -716,56 +771,56 @@ symbol sin with version GLIBC_2.2.5 from the dynamic library
"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
runtime dynamic linker.
-In external mode, 6l does not process any host object files, in
-particular foo.cgo2.o. It links together the 6g-generated object
+In external mode, cmd/link does not process any host object files, in
+particular foo.cgo2.o. It links together the gc-generated object
files, along with any other Go code, into a go.o file. While doing
-that, 6l will discover that there is no definition for
-_cgo_gcc_Cfunc_sin, referred to by the 6g-compiled source file. This
-is okay, because 6l also processes the cgo_import_static directive and
+that, cmd/link will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the gc-compiled source file. This
+is okay, because cmd/link also processes the cgo_import_static directive and
knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
-object file, so 6l does not treat the missing symbol as an error when
+object file, so cmd/link does not treat the missing symbol as an error when
creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
provided to the host linker by foo2.cgo.o, which in turn will need the
-symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
+symbol 'sin'. cmd/link also processes the cgo_ldflag directives, so that it
knows that the eventual host link command must include the -lm
argument, so that the host linker will be able to find 'sin' in the
math library.
-6l Command Line Interface
+cmd/link Command Line Interface
-The go command and any other Go-aware build systems invoke 6l
-to link a collection of packages into a single binary. By default, 6l will
+The go command and any other Go-aware build systems invoke cmd/link
+to link a collection of packages into a single binary. By default, cmd/link will
present the same interface it does today:
- 6l main.a
+ cmd/link main.a
-produces a file named 6.out, even if 6l does so by invoking the host
+produces a file named a.out, even if cmd/link does so by invoking the host
linker in external linking mode.
-By default, 6l will decide the linking mode as follows: if the only
+By default, cmd/link will decide the linking mode as follows: if the only
packages using cgo are those on a whitelist of standard library
-packages (net, os/user, runtime/cgo), 6l will use internal linking
-mode. Otherwise, there are non-standard cgo packages involved, and 6l
+packages (net, os/user, runtime/cgo), cmd/link will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
will use external linking mode. The first rule means that a build of
the godoc binary, which uses net but no other cgo, can run without
needing gcc available. The second rule means that a build of a
cgo-wrapped library like sqlite3 can generate a standalone executable
instead of needing to refer to a dynamic library. The specific choice
-can be overridden using a command line flag: 6l -linkmode=internal or
-6l -linkmode=external.
+can be overridden using a command line flag: cmd/link -linkmode=internal or
+cmd/link -linkmode=external.
-In an external link, 6l will create a temporary directory, write any
+In an external link, cmd/link will create a temporary directory, write any
host object files found in package archives to that directory (renamed
to avoid conflicts), write the go.o file to that directory, and invoke
the host linker. The default value for the host linker is $CC, split
into fields, or else "gcc". The specific host linker command line can
-be overridden using command line flags: 6l -extld=clang
+be overridden using command line flags: cmd/link -extld=clang
-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
other file compiled by the C++ compiler, the go tool will use the
-extld option to set the host linker to the C++ compiler.
These defaults mean that Go-aware build systems can ignore the linking
-changes and keep running plain '6l' and get reasonable results, but
+changes and keep running plain 'cmd/link' and get reasonable results, but
they can also control the linking details if desired.
*/
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index e0b89ec..fb5049c 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -38,8 +38,8 @@ var nameToC = map[string]string{
"ulong": "unsigned long",
"longlong": "long long",
"ulonglong": "unsigned long long",
- "complexfloat": "float complex",
- "complexdouble": "double complex",
+ "complexfloat": "float _Complex",
+ "complexdouble": "double _Complex",
}
// cname returns the C name to use for C.s.
@@ -167,6 +167,7 @@ func (p *Package) Translate(f *File) {
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
+ p.rewriteCalls(f)
p.rewriteRef(f)
}
@@ -575,6 +576,331 @@ func (p *Package) mangleName(n *Name) {
n.Mangle = prefix + n.Kind + "_" + n.Go
}
+// rewriteCalls rewrites all calls that pass pointers to check that
+// they follow the rules for passing pointers between Go and C.
+func (p *Package) rewriteCalls(f *File) {
+ for _, call := range f.Calls {
+ // This is a call to C.xxx; set goname to "xxx".
+ goname := call.Fun.(*ast.SelectorExpr).Sel.Name
+ if goname == "malloc" {
+ continue
+ }
+ name := f.Name[goname]
+ if name.Kind != "func" {
+ // Probably a type conversion.
+ continue
+ }
+ p.rewriteCall(f, call, name)
+ }
+}
+
+// rewriteCall rewrites one call to add pointer checks. We replace
+// each pointer argument x with _cgoCheckPointer(x).(T).
+func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
+ for i, param := range name.FuncType.Params {
+ if len(call.Args) <= i {
+ // Avoid a crash; this will be caught when the
+ // generated file is compiled.
+ return
+ }
+
+ // An untyped nil does not need a pointer check, and
+ // when _cgoCheckPointer returns the untyped nil the
+ // type assertion we are going to insert will fail.
+ // Easier to just skip nil arguments.
+ // TODO: Note that this fails if nil is shadowed.
+ if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" {
+ continue
+ }
+
+ if !p.needsPointerCheck(f, param.Go) {
+ continue
+ }
+
+ c := &ast.CallExpr{
+ Fun: ast.NewIdent("_cgoCheckPointer"),
+ Args: []ast.Expr{
+ call.Args[i],
+ },
+ }
+
+ // Add optional additional arguments for an address
+ // expression.
+ c.Args = p.checkAddrArgs(f, c.Args, call.Args[i])
+
+ // _cgoCheckPointer returns interface{}.
+ // We need to type assert that to the type we want.
+ // If the Go version of this C type uses
+ // unsafe.Pointer, we can't use a type assertion,
+ // because the Go file might not import unsafe.
+ // Instead we use a local variant of _cgoCheckPointer.
+
+ var arg ast.Expr
+ if n := p.unsafeCheckPointerName(param.Go); n != "" {
+ c.Fun = ast.NewIdent(n)
+ arg = c
+ } else {
+ // In order for the type assertion to succeed,
+ // we need it to match the actual type of the
+ // argument. The only type we have is the
+ // type of the function parameter. We know
+ // that the argument type must be assignable
+ // to the function parameter type, or the code
+ // would not compile, but there is nothing
+ // requiring that the types be exactly the
+ // same. Add a type conversion to the
+ // argument so that the type assertion will
+ // succeed.
+ c.Args[0] = &ast.CallExpr{
+ Fun: param.Go,
+ Args: []ast.Expr{
+ c.Args[0],
+ },
+ }
+
+ arg = &ast.TypeAssertExpr{
+ X: c,
+ Type: param.Go,
+ }
+ }
+
+ call.Args[i] = arg
+ }
+}
+
+// needsPointerCheck returns whether the type t needs a pointer check.
+// This is true if t is a pointer and if the value to which it points
+// might contain a pointer.
+func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
+ return p.hasPointer(f, t, true)
+}
+
+// hasPointer is used by needsPointerCheck. If top is true it returns
+// whether t is or contains a pointer that might point to a pointer.
+// If top is false it returns whether t is or contains a pointer.
+// f may be nil.
+func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
+ switch t := t.(type) {
+ case *ast.ArrayType:
+ if t.Len == nil {
+ if !top {
+ return true
+ }
+ return p.hasPointer(f, t.Elt, false)
+ }
+ return p.hasPointer(f, t.Elt, top)
+ case *ast.StructType:
+ for _, field := range t.Fields.List {
+ if p.hasPointer(f, field.Type, top) {
+ return true
+ }
+ }
+ return false
+ case *ast.StarExpr: // Pointer type.
+ if !top {
+ return true
+ }
+ return p.hasPointer(f, t.X, false)
+ case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+ return true
+ case *ast.Ident:
+ // TODO: Handle types defined within function.
+ for _, d := range p.Decl {
+ gd, ok := d.(*ast.GenDecl)
+ if !ok || gd.Tok != token.TYPE {
+ continue
+ }
+ for _, spec := range gd.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ if ts.Name.Name == t.Name {
+ return p.hasPointer(f, ts.Type, top)
+ }
+ }
+ }
+ if def := typedef[t.Name]; def != nil {
+ return p.hasPointer(f, def.Go, top)
+ }
+ if t.Name == "string" {
+ return !top
+ }
+ if t.Name == "error" {
+ return true
+ }
+ if goTypes[t.Name] != nil {
+ return false
+ }
+ // We can't figure out the type. Conservative
+ // approach is to assume it has a pointer.
+ return true
+ case *ast.SelectorExpr:
+ if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
+ // Type defined in a different package.
+ // Conservative approach is to assume it has a
+ // pointer.
+ return true
+ }
+ if f == nil {
+ // Conservative approach: assume pointer.
+ return true
+ }
+ name := f.Name[t.Sel.Name]
+ if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
+ return p.hasPointer(f, name.Type.Go, top)
+ }
+ // We can't figure out the type. Conservative
+ // approach is to assume it has a pointer.
+ return true
+ default:
+ error_(t.Pos(), "could not understand type %s", gofmt(t))
+ return true
+ }
+}
+
+// checkAddrArgs tries to add arguments to the call of
+// _cgoCheckPointer when the argument is an address expression. We
+// pass true to mean that the argument is an address operation of
+// something other than a slice index, which means that it's only
+// necessary to check the specific element pointed to, not the entire
+// object. This is for &s.f, where f is a field in a struct. We can
+// pass a slice or array, meaning that we should check the entire
+// slice or array but need not check any other part of the object.
+// This is for &s.a[i], where we need to check all of a. However, we
+// only pass the slice or array if we can refer to it without side
+// effects.
+func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
+ // Strip type conversions.
+ for {
+ c, ok := x.(*ast.CallExpr)
+ if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+ break
+ }
+ x = c.Args[0]
+ }
+ u, ok := x.(*ast.UnaryExpr)
+ if !ok || u.Op != token.AND {
+ return args
+ }
+ index, ok := u.X.(*ast.IndexExpr)
+ if !ok {
+ // This is the address of something that is not an
+ // index expression. We only need to examine the
+ // single value to which it points.
+ // TODO: what if true is shadowed?
+ return append(args, ast.NewIdent("true"))
+ }
+ if !p.hasSideEffects(f, index.X) {
+ // Examine the entire slice.
+ return append(args, index.X)
+ }
+ // Treat the pointer as unknown.
+ return args
+}
+
+// hasSideEffects returns whether the expression x has any side
+// effects. x is an expression, not a statement, so the only side
+// effect is a function call.
+func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
+ found := false
+ f.walk(x, "expr",
+ func(f *File, x interface{}, context string) {
+ switch x.(type) {
+ case *ast.CallExpr:
+ found = true
+ }
+ })
+ return found
+}
+
+// isType returns whether the expression is definitely a type.
+// This is conservative--it returns false for an unknown identifier.
+func (p *Package) isType(t ast.Expr) bool {
+ switch t := t.(type) {
+ case *ast.SelectorExpr:
+ if t.Sel.Name != "Pointer" {
+ return false
+ }
+ id, ok := t.X.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ return id.Name == "unsafe"
+ case *ast.Ident:
+ // TODO: This ignores shadowing.
+ switch t.Name {
+ case "unsafe.Pointer", "bool", "byte",
+ "complex64", "complex128",
+ "error",
+ "float32", "float64",
+ "int", "int8", "int16", "int32", "int64",
+ "rune", "string",
+ "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
+
+ return true
+ }
+ case *ast.StarExpr:
+ return p.isType(t.X)
+ case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
+ *ast.MapType, *ast.ChanType:
+
+ return true
+ }
+ return false
+}
+
+// unsafeCheckPointerName is given the Go version of a C type. If the
+// type uses unsafe.Pointer, we arrange to build a version of
+// _cgoCheckPointer that returns that type. This avoids using a type
+// assertion to unsafe.Pointer in our copy of user code. We return
+// the name of the _cgoCheckPointer function we are going to build, or
+// the empty string if the type does not use unsafe.Pointer.
+func (p *Package) unsafeCheckPointerName(t ast.Expr) string {
+ if !p.hasUnsafePointer(t) {
+ return ""
+ }
+ var buf bytes.Buffer
+ conf.Fprint(&buf, fset, t)
+ s := buf.String()
+ for i, t := range p.CgoChecks {
+ if s == t {
+ return p.unsafeCheckPointerNameIndex(i)
+ }
+ }
+ p.CgoChecks = append(p.CgoChecks, s)
+ return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
+}
+
+// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
+// t is the Go version of a C type, so we don't need to handle every case.
+// We only care about direct references, not references via typedefs.
+func (p *Package) hasUnsafePointer(t ast.Expr) bool {
+ switch t := t.(type) {
+ case *ast.Ident:
+ // We don't see a SelectorExpr for unsafe.Pointer;
+ // this is created by code in this file.
+ return t.Name == "unsafe.Pointer"
+ case *ast.ArrayType:
+ return p.hasUnsafePointer(t.Elt)
+ case *ast.StructType:
+ for _, f := range t.Fields.List {
+ if p.hasUnsafePointer(f.Type) {
+ return true
+ }
+ }
+ case *ast.StarExpr: // Pointer type.
+ return p.hasUnsafePointer(t.X)
+ }
+ return false
+}
+
+// unsafeCheckPointerNameIndex returns the name to use for a
+// _cgoCheckPointer variant based on the index in the CgoChecks slice.
+func (p *Package) unsafeCheckPointerNameIndex(i int) string {
+ return fmt.Sprintf("_cgoCheckPointer%d", i)
+}
+
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
// Go equivalents, now that we have figured out the meaning of all
// the xxx. In *godefs mode, rewriteRef replaces the names
@@ -612,6 +938,10 @@ func (p *Package) rewriteRef(f *File) {
if r.Name.Kind != "func" {
if r.Name.Kind == "type" {
r.Context = "type"
+ if r.Name.Type == nil {
+ error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ break
+ }
expr = r.Name.Type.Go
break
}
@@ -663,6 +993,10 @@ func (p *Package) rewriteRef(f *File) {
}
} else if r.Name.Kind == "type" {
// Okay - might be new(T)
+ if r.Name.Type == nil {
+ error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ break
+ }
expr = r.Name.Type.Go
} else if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
@@ -1028,12 +1362,12 @@ var dwarfToName = map[string]string{
"long unsigned int": "ulong",
"unsigned int": "uint",
"short unsigned int": "ushort",
+ "unsigned short": "ushort", // Used by Clang; issue 13129.
"short int": "short",
"long long int": "longlong",
"long long unsigned int": "ulonglong",
"signed char": "schar",
- "float complex": "complexfloat",
- "double complex": "complexdouble",
+ "unsigned char": "uchar",
}
const signedDelta = 64
@@ -1224,6 +1558,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.int32
case 8:
t.Go = c.int64
+ case 16:
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(t.Size),
+ Elt: c.uint8,
+ }
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
@@ -1381,6 +1720,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.uint32
case 8:
t.Go = c.uint64
+ case 16:
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(t.Size),
+ Elt: c.uint8,
+ }
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
@@ -1393,7 +1737,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
switch dtype.(type) {
- case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
s := dtype.Common().Name
if s != "" {
if ss, ok := dwarfToName[s]; ok {
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index 1b0ece2..aff616e 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -11,6 +11,7 @@ import (
"go/printer"
"go/token"
"os"
+ "path/filepath"
"strings"
)
@@ -19,7 +20,7 @@ func (p *Package) godefs(f *File, srcfile string) string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
- fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
+ fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
fmt.Fprintf(&buf, "\n")
override := make(map[string]string)
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index c8cd161..6171b9d 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -42,6 +42,7 @@ type Package struct {
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
+ CgoChecks []string // see unsafeCheckPointerName
}
// A File collects information about a single Go input file.
@@ -51,6 +52,7 @@ type File struct {
Package string // Package name
Preamble string // C preamble (doc comment on import "C")
Ref []*Ref // all references to C.xxx in AST
+ Calls []*ast.CallExpr // all calls to C.xxx in AST
ExpFunc []*ExpFunc // exported functions for this file
Name map[string]*Name // map from Go name to Name
}
@@ -132,43 +134,47 @@ func usage() {
}
var ptrSizeMap = map[string]int64{
- "386": 4,
- "alpha": 8,
- "amd64": 8,
- "arm": 4,
- "arm64": 8,
- "m68k": 4,
- "mipso32": 4,
- "mipsn32": 4,
- "mipso64": 8,
- "mipsn64": 8,
- "ppc": 4,
- "ppc64": 8,
- "ppc64le": 8,
- "s390": 4,
- "s390x": 8,
- "sparc": 4,
- "sparc64": 8,
+ "386": 4,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "m68k": 4,
+ "mipso32": 4,
+ "mipsn32": 4,
+ "mipso64": 8,
+ "mipsn64": 8,
+ "mips64": 8,
+ "mips64le": 8,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sparc": 4,
+ "sparc64": 8,
}
var intSizeMap = map[string]int64{
- "386": 4,
- "alpha": 8,
- "amd64": 8,
- "arm": 4,
- "arm64": 8,
- "m68k": 4,
- "mipso32": 4,
- "mipsn32": 4,
- "mipso64": 8,
- "mipsn64": 8,
- "ppc": 4,
- "ppc64": 8,
- "ppc64le": 8,
- "s390": 4,
- "s390x": 8,
- "sparc": 4,
- "sparc64": 8,
+ "386": 4,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "m68k": 4,
+ "mipso32": 4,
+ "mipsn32": 4,
+ "mipso64": 8,
+ "mipsn64": 8,
+ "mips64": 8,
+ "mips64le": 8,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sparc": 4,
+ "sparc64": 8,
}
var cPrefix string
@@ -297,11 +303,7 @@ func main() {
if nerrors > 0 {
os.Exit(2)
}
- pkg := f.Package
- if dir := os.Getenv("CGOPKGPATH"); dir != "" {
- pkg = filepath.Join(dir, pkg)
- }
- p.PackagePath = pkg
+ p.PackagePath = f.Package
p.Record(f)
if *godefs {
os.Stdout.WriteString(p.godefs(f, input))
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 90a7441..ca0ec0a 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -103,11 +103,19 @@ func (p *Package) writeDefs() {
}
if *gccgo {
+ fmt.Fprint(fgo2, gccgoGoProlog)
fmt.Fprint(fc, p.cPrologGccgo())
} else {
fmt.Fprint(fgo2, goProlog)
}
+ for i, t := range p.CgoChecks {
+ n := p.unsafeCheckPointerNameIndex(i)
+ fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
+ fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
+ fmt.Fprintf(fgo2, "}\n")
+ }
+
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
cVars := make(map[string]bool)
@@ -693,7 +701,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fntype := fn.Type
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
@@ -711,7 +719,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
npad++
}
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
@@ -744,8 +752,12 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
+ func(i int, aname string, atype ast.Expr) {
+ fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
})
fmt.Fprintf(fgcch, "};\n")
gccResult = "struct " + exp.ExpName + "_return"
@@ -758,7 +770,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
s += " recv"
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
s += ", "
}
@@ -783,7 +795,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
@@ -792,7 +804,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
} else {
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\treturn r;\n")
@@ -800,17 +812,18 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgcc, "}\n")
- // Build the wrapper function compiled by gc.
- goname := exp.Func.Name.Name
+ // Build the wrapper function compiled by cmd/compile.
+ goname := "_cgoexpwrap" + cPrefix + "_"
if fn.Recv != nil {
- goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
+ goname += fn.Recv.List[0].Names[0].Name + "_"
}
- fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
+ goname += exp.Func.Name.Name
+ fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
- fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
// The indirect here is converting from a Go function pointer to a C function pointer.
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
@@ -818,44 +831,75 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
- // Calling a function with a receiver from C requires
- // a Go wrapper function.
+ // This code uses printer.Fprint, not conf.Fprint,
+ // because we don't want //line comments in the middle
+ // of the function types.
+ fmt.Fprintf(fgo2, "\n")
+ fmt.Fprintf(fgo2, "func %s(", goname)
+ comma := false
if fn.Recv != nil {
- fmt.Fprintf(fgo2, "func %s(recv ", goname)
- conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgo2, ", p%d ", i)
- conf.Fprint(fgo2, fset, atype)
- })
- fmt.Fprintf(fgo2, ")")
- if gccResult != "void" {
- fmt.Fprint(fgo2, " (")
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- conf.Fprint(fgo2, fset, atype)
- })
- fmt.Fprint(fgo2, ")")
- }
- fmt.Fprint(fgo2, " {\n")
- fmt.Fprint(fgo2, "\t")
- if gccResult != "void" {
- fmt.Fprint(fgo2, "return ")
- }
- fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgo2, "recv ")
+ printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ comma = true
+ }
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if comma {
+ fmt.Fprintf(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
+ comma = true
+ })
+ fmt.Fprintf(fgo2, ")")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- fmt.Fprintf(fgo2, "p%d", i)
+ fmt.Fprintf(fgo2, "r%d ", i)
+ printer.Fprint(fgo2, fset, atype)
})
- fmt.Fprint(fgo2, ")\n")
- fmt.Fprint(fgo2, "}\n")
+ fmt.Fprint(fgo2, ")")
}
+ fmt.Fprint(fgo2, " {\n")
+ if gccResult == "void" {
+ fmt.Fprint(fgo2, "\t")
+ } else {
+ // Verify that any results don't contain any
+ // Go pointers.
+ addedDefer := false
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ if !p.hasPointer(nil, atype, false) {
+ return
+ }
+ if !addedDefer {
+ fmt.Fprint(fgo2, "\tdefer func() {\n")
+ addedDefer = true
+ }
+ fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
+ })
+ if addedDefer {
+ fmt.Fprint(fgo2, "\t}()\n")
+ }
+ fmt.Fprint(fgo2, "\treturn ")
+ }
+ if fn.Recv != nil {
+ fmt.Fprintf(fgo2, "recv.")
+ }
+ fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
}
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
@@ -879,13 +923,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
cdeclBuf := new(bytes.Buffer)
resultCount := 0
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) { resultCount++ })
+ func(i int, aname string, atype ast.Expr) { resultCount++ })
switch resultCount {
case 0:
fmt.Fprintf(cdeclBuf, "void")
case 1:
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
fmt.Fprintf(cdeclBuf, "%s", t.C)
})
@@ -894,9 +938,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
- fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
})
fmt.Fprintf(fgcch, "};\n")
fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
@@ -911,7 +959,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
// Function parameters.
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(cdeclBuf, ", ")
}
@@ -925,23 +973,15 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
}
+ fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams)
+
// We need to use a name that will be exported by the
// Go code; otherwise gccgo will make it static and we
// will not be able to link against it from the C
// code.
goName := "Cgoexp_" + exp.ExpName
- fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
- fmt.Fprint(fgcch, "\n")
-
- // Use a #define so that the C code that includes
- // cgo_export.h will be able to refer to the Go
- // function using the expected name.
- fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
-
- // Use a #undef in _cgo_export.c so that we ignore the
- // #define from cgo_export.h, since here we are
- // defining the real function.
- fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
+ fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
+ fmt.Fprint(fgcc, "\n")
fmt.Fprint(fgcc, "\n")
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
@@ -956,7 +996,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprint(fgcc, "recv")
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgcc, ", ")
}
@@ -982,7 +1022,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgo2, ", ")
}
@@ -993,7 +1033,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
if resultCount > 0 {
fmt.Fprintf(fgo2, " (")
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
@@ -1013,7 +1053,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
@@ -1071,19 +1111,19 @@ func (p *Package) gccgoSymbolPrefix() string {
}
// Call a function for each entry in an ast.FieldList, passing the
-// index into the list and the type.
-func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
+// index into the list, the name if any, and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
if fl == nil {
return
}
i := 0
for _, r := range fl.List {
if r.Names == nil {
- fn(i, r.Type)
+ fn(i, "", r.Type)
i++
} else {
- for range r.Names {
- fn(i, r.Type)
+ for _, n := range r.Names {
+ fn(i, n.Name, r.Type)
i++
}
}
@@ -1193,9 +1233,11 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
const gccProlog = `
-// Usual nonsense: if x and y are not equal, the type will be invalid
-// (have a negative array count) and an inscrutable error will come
-// out of the compiler and hopefully mention "name".
+/*
+ If x and y are not equal, the type will be invalid
+ (have a negative array count) and an inscrutable error will come
+ out of the compiler and hopefully mention "name".
+*/
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
// Check at compile time that the sizes we use match our expectations.
@@ -1239,6 +1281,18 @@ func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+
+//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+//go:linkname _cgoCheckResult runtime.cgoCheckResult
+func _cgoCheckResult(interface{})
+`
+
+const gccgoGoProlog = `
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+func _cgoCheckResult(interface{})
`
const goStringDef = `
@@ -1293,7 +1347,8 @@ var builtinDefs = map[string]string{
}
func (p *Package) cPrologGccgo() string {
- return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
+ return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
+ "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
}
const cPrologGccgo = `
@@ -1348,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
runtime_throw("runtime: C malloc failed");
return p;
}
+
+struct __go_type_descriptor;
+typedef struct __go_empty_interface {
+ const struct __go_type_descriptor *__type_descriptor;
+ void *__object;
+} Eface;
+
+extern Eface runtimeCgoCheckPointer(Eface, Slice)
+ __asm__("runtime.cgoCheckPointer")
+ __attribute__((weak));
+
+extern Eface localCgoCheckPointer(Eface, Slice)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
+
+Eface localCgoCheckPointer(Eface ptr, Slice args) {
+ if(runtimeCgoCheckPointer) {
+ return runtimeCgoCheckPointer(ptr, args);
+ }
+ return ptr;
+}
+
+extern void runtimeCgoCheckResult(Eface)
+ __asm__("runtime.cgoCheckResult")
+ __attribute__((weak));
+
+extern void localCgoCheckResult(Eface)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckResult");
+
+void localCgoCheckResult(Eface val) {
+ if(runtimeCgoCheckResult) {
+ runtimeCgoCheckResult(val);
+ }
+}
`
func (p *Package) gccExportHeaderProlog() string {
@@ -1373,14 +1461,16 @@ typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
-typedef __complex float GoComplex64;
-typedef __complex double GoComplex128;
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
-// static assertion to make sure the file is being used on architecture
-// at least with matching size of GoInt.
+/*
+ static assertion to make sure the file is being used on architecture
+ at least with matching size of GoInt.
+*/
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
-typedef struct { char *p; GoInt n; } GoString;
+typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;