@@ -139,6 +139,7 @@ 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 "syscall"
142143import "unsafe"
143144
144145var _ unsafe.Pointer
@@ -169,6 +170,13 @@ func __CBytes([]byte) unsafe.Pointer
169170func CBytes(b []byte) unsafe.Pointer {
170171 return C.__CBytes(b)
171172}
173+
174+ //go:linkname C.__get_errno_num runtime.cgo_errno
175+ func __get_errno_num() uintptr
176+
177+ func __get_errno() error {
178+ return syscall.Errno(C.__get_errno_num())
179+ }
172180`
173181
174182// Process extracts `import "C"` statements from the AST, parses the comment
@@ -225,7 +233,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
225233 switch decl := decl .(type ) {
226234 case * ast.FuncDecl :
227235 switch decl .Name .Name {
228- case "CString" , "GoString" , "GoStringN" , "__GoStringN" , "GoBytes" , "__GoBytes" , "CBytes" , "__CBytes" :
236+ case "CString" , "GoString" , "GoStringN" , "__GoStringN" , "GoBytes" , "__GoBytes" , "CBytes" , "__CBytes" , "__get_errno_num" , "__get_errno" :
229237 // Adjust the name to have a "C." prefix so it is correctly
230238 // resolved.
231239 decl .Name .Name = "C." + decl .Name .Name
@@ -1279,6 +1287,45 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
12791287// separate namespace (no _Cgo_ hacks like in gc).
12801288func (f * cgoFile ) walker (cursor * astutil.Cursor , names map [string ]clangCursor ) bool {
12811289 switch node := cursor .Node ().(type ) {
1290+ case * ast.AssignStmt :
1291+ // An assign statement could be something like this:
1292+ //
1293+ // val, errno := C.some_func()
1294+ //
1295+ // Check whether it looks like that, and if so, read the errno value and
1296+ // return it as the second return value. The call will be transformed
1297+ // into something like this:
1298+ //
1299+ // val, errno := C.some_func(), C.__get_errno()
1300+ if len (node .Lhs ) != 2 || len (node .Rhs ) != 1 {
1301+ return true
1302+ }
1303+ rhs , ok := node .Rhs [0 ].(* ast.CallExpr )
1304+ if ! ok {
1305+ return true
1306+ }
1307+ fun , ok := rhs .Fun .(* ast.SelectorExpr )
1308+ if ! ok {
1309+ return true
1310+ }
1311+ x , ok := fun .X .(* ast.Ident )
1312+ if ! ok {
1313+ return true
1314+ }
1315+ if found , ok := names [fun .Sel .Name ]; ok && x .Name == "C" {
1316+ // Replace "C"."some_func" into "C.somefunc".
1317+ rhs .Fun = & ast.Ident {
1318+ NamePos : x .NamePos ,
1319+ Name : f .getASTDeclName (fun .Sel .Name , found , true ),
1320+ }
1321+ // Add the errno value as the second value in the statement.
1322+ node .Rhs = append (node .Rhs , & ast.CallExpr {
1323+ Fun : & ast.Ident {
1324+ NamePos : node .Lhs [1 ].End (),
1325+ Name : "C.__get_errno" ,
1326+ },
1327+ })
1328+ }
12821329 case * ast.CallExpr :
12831330 fun , ok := node .Fun .(* ast.SelectorExpr )
12841331 if ! ok {
0 commit comments