Skip to content

Commit 6a0a441

Browse files
committed
cgo: implement rudimentary C array decaying
This is just a first step. It's not complete, but it gets some real world C code to parse. This signature, from the ESP-IDF: esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); Was previously converted to something like this (pseudocode): C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac [6]uint8) But this is not correct. C array parameters will decay. The array is passed by reference instead of by value. Instead, this would be the correct signature: C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac *uint8) So that it can be called like this (using CGo): var mac [6]byte errCode := C.esp_wifi_get_mac(C.ESP_IF_WIFI_AP, &mac[0]) This stores the result in the 6-element array mac.
1 parent b571c5c commit 6a0a441

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

cgo/libclang.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
196196
}
197197
fn.args = append(fn.args, paramInfo{
198198
name: argName,
199-
typeExpr: p.makeASTType(argType, pos),
199+
typeExpr: p.makeDecayingASTType(argType, pos),
200200
})
201201
}
202202
resultType := C.tinygo_clang_getCursorResultType(c)
@@ -391,6 +391,41 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
391391
})
392392
}
393393

394+
// makeDecayingASTType does the same as makeASTType but takes care of decaying
395+
// types (arrays in function parameters, etc). It is otherwise identical to
396+
// makeASTType.
397+
func (p *cgoPackage) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
398+
// Strip typedefs, if any.
399+
underlyingType := typ
400+
if underlyingType.kind == C.CXType_Typedef {
401+
c := C.tinygo_clang_getTypeDeclaration(typ)
402+
underlyingType = C.tinygo_clang_getTypedefDeclUnderlyingType(c)
403+
// TODO: support a chain of typedefs. At the moment, it seems to get
404+
// stuck in an endless loop when trying to get to the most underlying
405+
// type.
406+
}
407+
// Check for decaying type. An example would be an array type in a
408+
// parameter. This declaration:
409+
// void foo(char buf[6]);
410+
// is the same as this one:
411+
// void foo(char *buf);
412+
// But this one:
413+
// void bar(char buf[6][4]);
414+
// equals this:
415+
// void bar(char *buf[4]);
416+
// so not all array dimensions should be stripped, just the first one.
417+
// TODO: there are more kinds of decaying types.
418+
if underlyingType.kind == C.CXType_ConstantArray {
419+
// Apply type decaying.
420+
pointeeType := C.clang_getElementType(underlyingType)
421+
return &ast.StarExpr{
422+
Star: pos,
423+
X: p.makeASTType(pointeeType, pos),
424+
}
425+
}
426+
return p.makeASTType(typ, pos)
427+
}
428+
394429
// makeASTType return the ast.Expr for the given libclang type. In other words,
395430
// it converts a libclang type to a type in the Go AST.
396431
func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {

testdata/cgo/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,7 @@ void unionSetData(short f0, short f1, short f2) {
6161
globalUnion.data[1] = 8;
6262
globalUnion.data[2] = 1;
6363
}
64+
65+
void arraydecay(int buf1[5], int buf2[3][8], int buf3[4][7][2]) {
66+
// Do nothing.
67+
}

testdata/cgo/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ func main() {
125125
// Check whether CFLAGS are correctly passed on to compiled C files.
126126
println("CFLAGS value:", C.cflagsConstant)
127127

128+
// Check array-to-pointer decaying. This signature:
129+
// void arraydecay(int buf1[5], int buf2[3][8], int buf3[4][7][2]);
130+
// decays to:
131+
// void arraydecay(int *buf1, int *buf2[8], int *buf3[7][2]);
132+
C.arraydecay((*C.int)(nil), (*[8]C.int)(nil), (*[7][2]C.int)(nil))
133+
128134
// libc: test whether C functions work at all.
129135
buf1 := []byte("foobar\x00")
130136
buf2 := make([]byte, len(buf1))

testdata/cgo/main.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,7 @@ extern int cflagsConstant;
144144
// test duplicate definitions
145145
int add(int a, int b);
146146
extern int global;
147+
148+
// Test array decaying into a pointer.
149+
typedef int arraydecay_buf3[4][7][2];
150+
void arraydecay(int buf1[5], int buf2[3][8], arraydecay_buf3 buf3);

0 commit comments

Comments
 (0)