aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cgo/cgo.go17
-rw-r--r--cgo/libclang.go6
-rw-r--r--cgo/testdata/types.go10
-rw-r--r--cgo/testdata/types.out.go5
-rw-r--r--compiler/symbol.go33
-rw-r--r--testdata/cgo/main.c8
-rw-r--r--testdata/cgo/main.go4
-rw-r--r--testdata/cgo/main.h3
-rw-r--r--testdata/cgo/out.txt2
9 files changed, 77 insertions, 11 deletions
diff --git a/cgo/cgo.go b/cgo/cgo.go
index 7cc61b9ce..73d26e1d8 100644
--- a/cgo/cgo.go
+++ b/cgo/cgo.go
@@ -54,9 +54,10 @@ type constantInfo struct {
// functionInfo stores some information about a CGo function found by libclang
// and declared in the AST.
type functionInfo struct {
- args []paramInfo
- results *ast.FieldList
- pos token.Pos
+ args []paramInfo
+ results *ast.FieldList
+ pos token.Pos
+ variadic bool
}
// paramInfo is a parameter of a CGo function (see functionInfo).
@@ -484,6 +485,16 @@ func (p *cgoPackage) addFuncDecls() {
Results: fn.results,
},
}
+ if fn.variadic {
+ decl.Doc = &ast.CommentGroup{
+ List: []*ast.Comment{
+ &ast.Comment{
+ Slash: fn.pos,
+ Text: "//go:variadic",
+ },
+ },
+ }
+ }
obj.Decl = decl
for i, arg := range fn.args {
args[i] = &ast.Field{
diff --git a/cgo/libclang.go b/cgo/libclang.go
index 649494f12..f1ba3baa1 100644
--- a/cgo/libclang.go
+++ b/cgo/libclang.go
@@ -152,12 +152,10 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
return C.CXChildVisit_Continue
}
cursorType := C.tinygo_clang_getCursorType(c)
- if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
- return C.CXChildVisit_Continue // not supported
- }
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
fn := &functionInfo{
- pos: pos,
+ pos: pos,
+ variadic: C.clang_isFunctionTypeVariadic(cursorType) != 0,
}
p.functions[name] = fn
for i := 0; i < numArgs; i++ {
diff --git a/cgo/testdata/types.go b/cgo/testdata/types.go
index 2aa0982a4..9edec55df 100644
--- a/cgo/testdata/types.go
+++ b/cgo/testdata/types.go
@@ -104,6 +104,10 @@ typedef struct {
unsigned char e : 3;
// Note that C++ allows bitfields bigger than the underlying type.
} bitfield_t;
+
+// Function signatures.
+void variadic0();
+void variadic2(int x, int y, ...);
*/
import "C"
@@ -163,3 +167,9 @@ func accessUnion() {
var _ *C.int = union2d.unionfield_i()
var _ *[2]float64 = union2d.unionfield_d()
}
+
+// Test function signatures.
+func accessFunctions() {
+ C.variadic0()
+ C.variadic2(3, 5)
+}
diff --git a/cgo/testdata/types.out.go b/cgo/testdata/types.out.go
index af638b9e7..c825d5dd5 100644
--- a/cgo/testdata/types.out.go
+++ b/cgo/testdata/types.out.go
@@ -4,6 +4,11 @@ import "unsafe"
var _ unsafe.Pointer
+func C.variadic0() //go:variadic
+func C.variadic2(x C.int, y C.int) //go:variadic
+var C.variadic0$funcaddr unsafe.Pointer
+var C.variadic2$funcaddr unsafe.Pointer
+
const C.option2A = 20
const C.optionA = 0
const C.optionB = 1
diff --git a/compiler/symbol.go b/compiler/symbol.go
index 10051be6c..348eb5255 100644
--- a/compiler/symbol.go
+++ b/compiler/symbol.go
@@ -25,6 +25,7 @@ type functionInfo struct {
linkName string // go:linkname, go:export
exported bool // go:export, CGo
nobounds bool // go:nobounds
+ variadic bool // go:variadic (CGo only)
inline inlineType // go:inline
}
@@ -88,8 +89,23 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
paramTypes = append(paramTypes, info.llvmType)
}
- fnType := llvm.FunctionType(retType, paramTypes, false)
+ fnType := llvm.FunctionType(retType, paramTypes, info.variadic)
llvmFn = llvm.AddFunction(c.mod, info.linkName, fnType)
+ if strings.HasPrefix(c.Triple, "wasm") {
+ // C functions without prototypes like this:
+ // void foo();
+ // are actually variadic functions. However, it appears that it has been
+ // decided in WebAssembly that such prototype-less functions are not
+ // allowed in WebAssembly.
+ // In C, this can only happen when there are zero parameters, hence this
+ // check here. For more information:
+ // https://reviews.llvm.org/D48443
+ // https://github.com/WebAssembly/tool-conventions/issues/16
+ if info.variadic && len(fn.Params) == 0 {
+ attr := c.ctx.CreateStringAttribute("no-prototype", "")
+ llvmFn.AddFunctionAttr(attr)
+ }
+ }
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
for i, info := range paramInfos {
@@ -162,10 +178,9 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
} else {
// Pick the default linkName.
info.linkName = f.RelString(nil)
- // Check for //go: pragmas, which may change the link name (among
- // others).
- info.parsePragmas(f)
}
+ // Check for //go: pragmas, which may change the link name (among others).
+ info.parsePragmas(f)
return info
}
@@ -223,6 +238,16 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
if hasUnsafeImport(f.Pkg.Pkg) {
info.nobounds = true
}
+ case "//go:variadic":
+ // The //go:variadic pragma is emitted by the CGo preprocessing
+ // pass for C variadic functions. This includes both explicit
+ // (with ...) and implicit (no parameters in signature)
+ // functions.
+ if strings.HasPrefix(f.Name(), "C.") {
+ // This prefix cannot naturally be created, it must have
+ // been created as a result of CGo preprocessing.
+ info.variadic = true
+ }
}
}
}
diff --git a/testdata/cgo/main.c b/testdata/cgo/main.c
index 8f3b09464..3a2e9c57e 100644
--- a/testdata/cgo/main.c
+++ b/testdata/cgo/main.c
@@ -34,6 +34,14 @@ int doCallback(int a, int b, binop_t callback) {
return callback(a, b);
}
+int variadic0() {
+ return 1;
+}
+
+int variadic2(int x, int y, ...) {
+ return x * y;
+}
+
void store(int value, int *ptr) {
*ptr = value;
}
diff --git a/testdata/cgo/main.go b/testdata/cgo/main.go
index 616bc5bfc..d9e2d7297 100644
--- a/testdata/cgo/main.go
+++ b/testdata/cgo/main.go
@@ -36,6 +36,10 @@ func main() {
cb = C.binop_t(C.mul)
println("callback 2:", C.doCallback(20, 30, cb))
+ // variadic functions
+ println("variadic0:", C.variadic0())
+ println("variadic2:", C.variadic2(3, 5))
+
// equivalent types
var goInt8 int8 = 5
var _ C.int8_t = goInt8
diff --git a/testdata/cgo/main.h b/testdata/cgo/main.h
index b4ac4ee88..857a796ef 100644
--- a/testdata/cgo/main.h
+++ b/testdata/cgo/main.h
@@ -10,6 +10,9 @@ int doCallback(int a, int b, binop_t cb);
typedef int * intPointer;
void store(int value, int *ptr);
+int variadic0();
+int variadic2(int x, int y, ...);
+
# define CONST_INT 5
# define CONST_INT2 5llu
# define CONST_FLOAT 5.8
diff --git a/testdata/cgo/out.txt b/testdata/cgo/out.txt
index 9da7386a1..31fd4d330 100644
--- a/testdata/cgo/out.txt
+++ b/testdata/cgo/out.txt
@@ -12,6 +12,8 @@ defined char: 99
25: 25
callback 1: 50
callback 2: 600
+variadic0: 1
+variadic2: 15
bool: true true
float: +3.100000e+000
double: +3.200000e+000