cgo: add support for variadic functions
This doesn't yet add support for actually making use of variadic functions, but at least allows (unintended) variadic functions like the following to work: void foo();
Этот коммит содержится в:
родитель
5502182642
коммит
2e9c3a1d8d
9 изменённых файлов: 77 добавлений и 11 удалений
17
cgo/cgo.go
17
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{
|
||||
|
|
|
@ -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++ {
|
||||
|
|
10
cgo/testdata/types.go
предоставленный
10
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)
|
||||
}
|
||||
|
|
5
cgo/testdata/types.out.go
предоставленный
5
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
testdata/cgo/main.c
предоставленный
8
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;
|
||||
}
|
||||
|
|
4
testdata/cgo/main.go
предоставленный
4
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
|
||||
|
|
3
testdata/cgo/main.h
предоставленный
3
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
|
||||
|
|
2
testdata/cgo/out.txt
предоставленный
2
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
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче