Skip to content

Commit

Permalink
Pass fixed-size arrays as slices. Fixes #736 (#737)
Browse files Browse the repository at this point in the history
When passing arrays of fixed length around as parameters, Go passes them by value, making a copy.
Any changes to the copied array will not change the initial array values. To have the same behaviour as in C, we need to always pass arrays as slices.
This is also required for calls to library functions like UnsafeSliceToSlice and Fread.
  • Loading branch information
kamphaus authored and elliotchance committed Jun 3, 2018
1 parent 994be62 commit a3ca656
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 8 deletions.
4 changes: 2 additions & 2 deletions noarch/stdio.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ func Ftell(f *File) int32 {
// read.
//
// The total amount of bytes read if successful is (size*count).
func Fread(ptr *[]byte, size1, size2 int32, f *File) int32 {
func Fread(ptr []byte, size1, size2 int32, f *File) int32 {
// Create a new buffer so that we can ensure we read up to the correct
// number of bytes from the file.
newBuffer := make([]byte, size1*size2)
Expand All @@ -635,7 +635,7 @@ func Fread(ptr *[]byte, size1, size2 int32, f *File) int32 {
// Despite any error we need to make sure the bytes read are copied to the
// destination buffer.
for i, b := range newBuffer {
(*ptr)[i] = b
ptr[i] = b
}

// Now we can handle the success or failure.
Expand Down
2 changes: 1 addition & 1 deletion program/function_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ var builtInFunctionDefinitions = map[string][]string{
"int putc(int, FILE*) -> noarch.Fputc",
"int fseek(FILE*, long int, int) -> noarch.Fseek",
"long ftell(FILE*) -> noarch.Ftell",
"int fread(void*, int, int, FILE*) -> $0 = noarch.Fread(&1, $2, $3, $4)",
"int fread(void*, int, int, FILE*) -> noarch.Fread",
"int fwrite(char*, int, int, FILE*) -> noarch.Fwrite",
"int fgetpos(FILE*, int*) -> noarch.Fgetpos",
"int fsetpos(FILE*, int*) -> noarch.Fsetpos",
Expand Down
29 changes: 28 additions & 1 deletion tests/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ typedef struct mem {
int b;
} mem;

typedef struct mem2 {
int a[2];
} mem2;
typedef int altint;

void setptr(int *arr, int val) {
arr[0] = val;
}
void setarr(int arr[], int val) {
arr[0] = val;
}

int main()
{
plan(74);
plan(80);

diag("TODO: __builtin_object_size")
// https://github.com/elliotchance/c2go/issues/359
Expand Down Expand Up @@ -244,6 +256,21 @@ int main()
is_eq(dest7[0].b, 3.0);
is_eq(dest7[1].a, 0);
is_eq(dest7[1].b, 0.0);
mem2 dest8;
dest8.a[0] = 42;
memset(dest8.a, 0, sizeof(int)*2);
is_eq(dest8.a[0], 0);
is_eq(dest8.a[1], 0);
dest8.a[0] = 42;
mem2 dest9;
altint *test = (altint *) dest9.a;
memcpy(dest9.a, dest8.a, sizeof(int)*2);
is_eq(dest9.a[0], 42);
is_eq(test[0], 42);
setarr(dest9.a, 1);
is_eq(dest9.a[0], 1);
setptr(dest9.a, 2);
is_eq(dest9.a[0], 2);
}
{
diag("memcmp");
Expand Down
10 changes: 7 additions & 3 deletions transpiler/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,13 @@ func transpileCallExpr(n *ast.CallExpr, p *program.Program) (
var varName string
if v, ok := element[0].(*goast.Ident); ok {
varName = v.Name
} else {
return nil, "", nil, nil,
fmt.Errorf("golang ast for variable name have type %T, expect ast.Ident", element[3])
} else if se, ok := element[0].(*goast.SliceExpr); ok {
if v, ok2 := se.X.(*goast.Ident); ok2 {
varName = v.Name
} else {
return nil, "", nil, nil,
fmt.Errorf("golang ast for variable name have type %T, expect ast.Ident", element[0])
}
}

p.AddImport("sort")
Expand Down
2 changes: 1 addition & 1 deletion transpiler/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr
return
}

if !types.IsFunction(exprType) && n.Kind != ast.ImplicitCastExprArrayToPointerDecay {
if !types.IsFunction(exprType) && !strings.ContainsAny(n.Type, "[]") {
expr, err = types.CastExpr(p, expr, exprType, n.Type)
if err != nil {
return nil, "", nil, nil, err
Expand Down
5 changes: 5 additions & 0 deletions transpiler/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program,
}
preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

if se, ok := expression.(*goast.SliceExpr); ok && se.High == nil && se.Low == nil && se.Max == nil {
// simplify the expression
expression = se.X
}

isConst, indexInt := util.EvaluateConstExpr(index)
if isConst && indexInt < 0 {
indexInt = -indexInt
Expand Down
3 changes: 3 additions & 0 deletions types/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,9 @@ func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) (
if err != nil {
return nil, err
}
if _, arrSize := GetArrayTypeAndSize(cFromType); arrSize > 0 {
expr = &goast.SliceExpr{X: expr}
}
return &goast.StarExpr{
X: &goast.CallExpr{
Fun: &goast.StarExpr{
Expand Down

0 comments on commit a3ca656

Please sign in to comment.