@@ -130,6 +130,9 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) erro
130130 // Declare functions found by libclang.
131131 info .addFuncDecls ()
132132
133+ // Declare stub function pointer values found by libclang.
134+ info .addFuncPtrDecls ()
135+
133136 // Declare globals found by libclang.
134137 info .addVarDecls ()
135138
@@ -199,6 +202,55 @@ func (info *fileInfo) addFuncDecls() {
199202 }
200203}
201204
205+ // addFuncPtrDecls creates stub declarations of function pointer values. These
206+ // values will later be replaced with the real values in the compiler.
207+ // It adds code like the following to the AST:
208+ //
209+ // var (
210+ // C.add unsafe.Pointer
211+ // C.mul unsafe.Pointer
212+ // // ...
213+ // )
214+ func (info * fileInfo ) addFuncPtrDecls () {
215+ gen := & ast.GenDecl {
216+ TokPos : info .importCPos ,
217+ Tok : token .VAR ,
218+ Lparen : info .importCPos ,
219+ Rparen : info .importCPos ,
220+ }
221+ names := make ([]string , 0 , len (info .functions ))
222+ for name := range info .functions {
223+ names = append (names , name )
224+ }
225+ sort .Strings (names )
226+ for _ , name := range names {
227+ obj := & ast.Object {
228+ Kind : ast .Typ ,
229+ Name : "C." + name + "$funcaddr" ,
230+ }
231+ valueSpec := & ast.ValueSpec {
232+ Names : []* ast.Ident {& ast.Ident {
233+ NamePos : info .importCPos ,
234+ Name : "C." + name + "$funcaddr" ,
235+ Obj : obj ,
236+ }},
237+ Type : & ast.SelectorExpr {
238+ X : & ast.Ident {
239+ NamePos : info .importCPos ,
240+ Name : "unsafe" ,
241+ },
242+ Sel : & ast.Ident {
243+ NamePos : info .importCPos ,
244+ Name : "Pointer" ,
245+ },
246+ },
247+ }
248+ obj .Decl = valueSpec
249+ gen .Specs = append (gen .Specs , valueSpec )
250+ }
251+ info .Decls = append (info .Decls , gen )
252+ }
253+
202254// addVarDecls declares external C globals in the Go source.
203255// It adds code like the following to the AST:
204256//
@@ -327,15 +379,34 @@ func (info *fileInfo) addTypedefs() {
327379// separate namespace (no _Cgo_ hacks like in gc).
328380func (info * fileInfo ) walker (cursor * astutil.Cursor ) bool {
329381 switch node := cursor .Node ().(type ) {
382+ case * ast.CallExpr :
383+ fun , ok := node .Fun .(* ast.SelectorExpr )
384+ if ! ok {
385+ return true
386+ }
387+ x , ok := fun .X .(* ast.Ident )
388+ if ! ok {
389+ return true
390+ }
391+ if _ , ok := info .functions [fun .Sel .Name ]; ok && x .Name == "C" {
392+ node .Fun = & ast.Ident {
393+ NamePos : x .NamePos ,
394+ Name : "C." + fun .Sel .Name ,
395+ }
396+ }
330397 case * ast.SelectorExpr :
331398 x , ok := node .X .(* ast.Ident )
332399 if ! ok {
333400 return true
334401 }
335402 if x .Name == "C" {
403+ name := "C." + node .Sel .Name
404+ if _ , ok := info .functions [node .Sel .Name ]; ok {
405+ name += "$funcaddr"
406+ }
336407 cursor .Replace (& ast.Ident {
337408 NamePos : x .NamePos ,
338- Name : "C." + node . Sel . Name ,
409+ Name : name ,
339410 })
340411 }
341412 }
0 commit comments