Commit 03876af9 authored by Hiroshi Ioka's avatar Hiroshi Ioka Committed by Ian Lance Taylor

cmd/cgo: support niladic function-like macros

Currently, cgo supports only macros which can be reduced to constants
or variables. The CL addresses remaining parts, macros which can be
represented as niladic functions.

The basic idea is simple:
  1. make a thin wrapper function per macros.
  2. replace macro expansions with function calls.

Fixes #10715
Fixes #18720

Change-Id: I150b4fb48e9dc4cc34466ef6417c04ac93d4bc1a
Reviewed-on: https://go-review.googlesource.com/43970
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent c1679286
...@@ -219,12 +219,5 @@ func fixcgo() { ...@@ -219,12 +219,5 @@ func fixcgo() {
// cgo1 and cgo2 don't run on netbsd, srandom has a different signature // cgo1 and cgo2 don't run on netbsd, srandom has a different signature
skipTest("cgo1") skipTest("cgo1")
skipTest("cgo2") skipTest("cgo2")
// cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly, see issue #10715.
skipTest("cgo3")
skipTest("cgo4")
case "openbsd", "solaris":
// cgo3 and cgo4 don't run on openbsd and solaris, since cgo cannot handle stdout correctly, see issue #10715.
skipTest("cgo3")
skipTest("cgo4")
} }
} }
...@@ -12,13 +12,39 @@ package cgotest ...@@ -12,13 +12,39 @@ package cgotest
struct foo { char c; }; struct foo { char c; };
#define SIZE_OF(x) sizeof(x) #define SIZE_OF(x) sizeof(x)
#define SIZE_OF_FOO SIZE_OF(struct foo) #define SIZE_OF_FOO SIZE_OF(struct foo)
#define VAR1 VAR
#define VAR var
int var = 5;
#define ADDR &var
#define CALL fn()
int fn(void) {
return ++var;
}
*/ */
import "C" import "C"
import "testing" import "testing"
func test18720(t *testing.T) { func test18720(t *testing.T) {
if C.HELLO_WORLD != "hello\000world" { if got, want := C.HELLO_WORLD, "hello\000world"; got != want {
t.Fatalf(`expected "hello\000world", but got %q`, C.HELLO_WORLD) t.Errorf("C.HELLO_WORLD == %q, expected %q", got, want)
}
if got, want := C.VAR1, C.int(5); got != want {
t.Errorf("C.VAR1 == %v, expected %v", got, want)
}
if got, want := *C.ADDR, C.int(5); got != want {
t.Errorf("*C.ADDR == %v, expected %v", got, want)
}
if got, want := C.CALL, C.int(6); got != want {
t.Errorf("C.CALL == %v, expected %v", got, want)
}
if got, want := C.CALL, C.int(7); got != want {
t.Errorf("C.CALL == %v, expected %v", got, want)
} }
// Issue 20125. // Issue 20125.
......
...@@ -264,10 +264,6 @@ func (p *Package) guessKinds(f *File) []*Name { ...@@ -264,10 +264,6 @@ func (p *Package) guessKinds(f *File) []*Name {
if n.IsConst() { if n.IsConst() {
continue continue
} }
if isName(n.Define) {
n.C = n.Define
}
} }
// If this is a struct, union, or enum type name, no need to guess the kind. // If this is a struct, union, or enum type name, no need to guess the kind.
...@@ -1073,7 +1069,17 @@ func (p *Package) rewriteRef(f *File) { ...@@ -1073,7 +1069,17 @@ func (p *Package) rewriteRef(f *File) {
// Assign mangled names. // Assign mangled names.
for _, n := range f.Name { for _, n := range f.Name {
if n.Kind == "not-type" { if n.Kind == "not-type" {
n.Kind = "var" if n.Define == "" {
n.Kind = "var"
} else {
n.Kind = "macro"
n.FuncType = &FuncType{
Result: n.Type,
Go: &ast.FuncType{
Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
},
}
}
} }
if n.Mangle == "" { if n.Mangle == "" {
p.mangleName(n) p.mangleName(n)
...@@ -1127,7 +1133,8 @@ func (p *Package) rewriteRef(f *File) { ...@@ -1127,7 +1133,8 @@ func (p *Package) rewriteRef(f *File) {
break break
} }
case "expr": case "expr":
if r.Name.Kind == "func" { switch r.Name.Kind {
case "func":
if builtinDefs[r.Name.C] != "" { if builtinDefs[r.Name.C] != "" {
error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C)) error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
} }
...@@ -1154,24 +1161,24 @@ func (p *Package) rewriteRef(f *File) { ...@@ -1154,24 +1161,24 @@ func (p *Package) rewriteRef(f *File) {
Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
Args: []ast.Expr{ast.NewIdent(name.Mangle)}, Args: []ast.Expr{ast.NewIdent(name.Mangle)},
} }
} else if r.Name.Kind == "type" { case "type":
// Okay - might be new(T) // Okay - might be new(T)
if r.Name.Type == nil { if r.Name.Type == nil {
error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
break break
} }
expr = r.Name.Type.Go expr = r.Name.Type.Go
} else if r.Name.Kind == "var" { case "var":
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
case "macro":
expr = &ast.CallExpr{Fun: expr}
} }
case "selector": case "selector":
if r.Name.Kind == "var" { if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
} else { } else {
error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go)) error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
} }
case "type": case "type":
if r.Name.Kind != "type" { if r.Name.Kind != "type" {
error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
......
...@@ -89,7 +89,7 @@ type Name struct { ...@@ -89,7 +89,7 @@ type Name struct {
Mangle string // name used in generated Go Mangle string // name used in generated Go
C string // name used in C C string // name used in C
Define string // #define expansion Define string // #define expansion
Kind string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type" Kind string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
Type *Type // the type of xxx Type *Type // the type of xxx
FuncType *FuncType FuncType *FuncType
AddError bool AddError bool
......
...@@ -400,10 +400,12 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { ...@@ -400,10 +400,12 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
inProlog := builtinDefs[name] != "" inProlog := builtinDefs[name] != ""
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
paramnames := []string(nil) paramnames := []string(nil)
for i, param := range d.Type.Params.List { if d.Type.Params != nil {
paramName := fmt.Sprintf("p%d", i) for i, param := range d.Type.Params.List {
param.Names = []*ast.Ident{ast.NewIdent(paramName)} paramName := fmt.Sprintf("p%d", i)
paramnames = append(paramnames, paramName) param.Names = []*ast.Ident{ast.NewIdent(paramName)}
paramnames = append(paramnames, paramName)
}
} }
if *gccgo { if *gccgo {
...@@ -502,8 +504,10 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { ...@@ -502,8 +504,10 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
} }
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n") fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
for i := range d.Type.Params.List { if d.Type.Params != nil {
fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) for i := range d.Type.Params.List {
fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
}
} }
fmt.Fprintf(fgo2, "\t}\n") fmt.Fprintf(fgo2, "\t}\n")
fmt.Fprintf(fgo2, "\treturn\n") fmt.Fprintf(fgo2, "\treturn\n")
...@@ -615,14 +619,18 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { ...@@ -615,14 +619,18 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ") fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
} }
} }
fmt.Fprintf(fgcc, "%s(", n.C) if n.Kind == "macro" {
for i := range n.FuncType.Params { fmt.Fprintf(fgcc, "%s;\n", n.C)
if i > 0 { } else {
fmt.Fprintf(fgcc, ", ") fmt.Fprintf(fgcc, "%s(", n.C)
for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
fmt.Fprintf(fgcc, "a->p%d", i)
} }
fmt.Fprintf(fgcc, "a->p%d", i) fmt.Fprintf(fgcc, ");\n")
} }
fmt.Fprintf(fgcc, ");\n")
if n.AddError { if n.AddError {
fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n") fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n")
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment