@@ -139,7 +139,10 @@ typedef unsigned long long _Cgo_ulonglong;
139139// These functions will be modified to get a "C." prefix, so the source below
140140// doesn't reflect the final AST.
141141const generatedGoFilePrefix = `
142- import "unsafe"
142+ import (
143+ "syscall"
144+ "unsafe"
145+ )
143146
144147var _ unsafe.Pointer
145148
@@ -169,6 +172,13 @@ func __CBytes([]byte) unsafe.Pointer
169172func CBytes(b []byte) unsafe.Pointer {
170173 return C.__CBytes(b)
171174}
175+
176+ //go:linkname C.__get_errno_num runtime.cgo_errno
177+ func __get_errno_num() uintptr
178+
179+ func __get_errno() error {
180+ return syscall.Errno(C.__get_errno_num())
181+ }
172182`
173183
174184// Process extracts `import "C"` statements from the AST, parses the comment
@@ -225,7 +235,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
225235 switch decl := decl .(type ) {
226236 case * ast.FuncDecl :
227237 switch decl .Name .Name {
228- case "CString" , "GoString" , "GoStringN" , "__GoStringN" , "GoBytes" , "__GoBytes" , "CBytes" , "__CBytes" :
238+ case "CString" , "GoString" , "GoStringN" , "__GoStringN" , "GoBytes" , "__GoBytes" , "CBytes" , "__CBytes" , "__get_errno_num" , "__get_errno" :
229239 // Adjust the name to have a "C." prefix so it is correctly
230240 // resolved.
231241 decl .Name .Name = "C." + decl .Name .Name
@@ -1279,6 +1289,45 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
12791289// separate namespace (no _Cgo_ hacks like in gc).
12801290func (f * cgoFile ) walker (cursor * astutil.Cursor , names map [string ]clangCursor ) bool {
12811291 switch node := cursor .Node ().(type ) {
1292+ case * ast.AssignStmt :
1293+ // An assign statement could be something like this:
1294+ //
1295+ // val, errno := C.some_func()
1296+ //
1297+ // Check whether it looks like that, and if so, read the errno value and
1298+ // return it as the second return value. The call will be transformed
1299+ // into something like this:
1300+ //
1301+ // val, errno := C.some_func(), C.__get_errno()
1302+ if len (node .Lhs ) != 2 || len (node .Rhs ) != 1 {
1303+ return true
1304+ }
1305+ rhs , ok := node .Rhs [0 ].(* ast.CallExpr )
1306+ if ! ok {
1307+ return true
1308+ }
1309+ fun , ok := rhs .Fun .(* ast.SelectorExpr )
1310+ if ! ok {
1311+ return true
1312+ }
1313+ x , ok := fun .X .(* ast.Ident )
1314+ if ! ok {
1315+ return true
1316+ }
1317+ if found , ok := names [fun .Sel .Name ]; ok && x .Name == "C" {
1318+ // Replace "C"."some_func" into "C.somefunc".
1319+ rhs .Fun = & ast.Ident {
1320+ NamePos : x .NamePos ,
1321+ Name : f .getASTDeclName (fun .Sel .Name , found , true ),
1322+ }
1323+ // Add the errno value as the second value in the statement.
1324+ node .Rhs = append (node .Rhs , & ast.CallExpr {
1325+ Fun : & ast.Ident {
1326+ NamePos : node .Lhs [1 ].End (),
1327+ Name : "C.__get_errno" ,
1328+ },
1329+ })
1330+ }
12821331 case * ast.CallExpr :
12831332 fun , ok := node .Fun .(* ast.SelectorExpr )
12841333 if ! ok {
0 commit comments