authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-13 22:40:38-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-16 19:36:33-04:00
log59b3dc8907f76b93caa689732e878a5bfa2f65c2
treeced7464c4d054ebeaf413e46454b8dc820b1249e
parenta7d59086b49b0ae11a4830d2ea72b63be05fab94

allow passing by non-copying value

closes #733

4 files changed, 31 insertions(+), 53 deletions(-)

doc/langref.html.in+14-23
......@@ -2797,39 +2797,30 @@ fn foo() void { }
27972797 {#code_end#}
27982798 {#header_open|Pass-by-value Parameters#}
27992799 <p>
2800 In Zig, structs, unions, and enums with payloads cannot be passed by value
2801 to a function.
2800 In Zig, structs, unions, and enums with payloads can be passed directly to a function:
28022801 </p>
2803 {#code_begin|test_err|not copyable; cannot pass by value#}
2804const Foo = struct {
2802 {#code_begin|test#}
2803const Point = struct {
28052804 x: i32,
2805 y: i32,
28062806};
28072807
2808fn bar(foo: Foo) void {}
2809
2810test "pass aggregate type by value to function" {
2811 bar(Foo {.x = 12,});
2808fn foo(point: Point) i32 {
2809 return point.x + point.y;
28122810}
2813 {#code_end#}
2814 <p>
2815 Instead, one must use <code>*const</code>. Zig allows implicitly casting something
2816 to a const pointer to it:
2817 </p>
2818 {#code_begin|test#}
2819const Foo = struct {
2820 x: i32,
2821};
28222811
2823fn bar(foo: *const Foo) void {}
2812const assert = @import("std").debug.assert;
28242813
2825test "implicitly cast to const pointer" {
2826 bar(Foo {.x = 12,});
2814test "pass aggregate type by non-copy value to function" {
2815 assert(foo(Point{ .x = 1, .y = 2 }) == 3);
28272816}
28282817 {#code_end#}
28292818 <p>
2830 However,
2831 the C ABI does allow passing structs and unions by value. So functions which
2832 use the C calling convention may pass structs and unions by value.
2819 In this case, the value may be passed by reference, or by value, whichever way
2820 Zig decides will be faster.
2821 </p>
2822 <p>
2823 For extern functions, Zig follows the C ABI for passing structs and unions by value.
28332824 </p>
28342825 {#header_close#}
28352826 {#header_open|Function Reflection#}
src/analyze.cpp+4-7
......@@ -1135,7 +1135,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11351135 gen_param_info->src_index = i;
11361136 gen_param_info->gen_index = SIZE_MAX;
11371137
1138 type_ensure_zero_bits_known(g, type_entry);
1138 ensure_complete_type(g, type_entry);
1139 if (type_is_invalid(type_entry))
1140 return g->builtin_types.entry_invalid;
1141
11391142 if (type_has_bits(type_entry)) {
11401143 TypeTableEntry *gen_type;
11411144 if (handle_is_ptr(type_entry)) {
......@@ -1546,12 +1549,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15461549 case TypeTableEntryIdUnion:
15471550 case TypeTableEntryIdFn:
15481551 case TypeTableEntryIdPromise:
1549 ensure_complete_type(g, type_entry);
1550 if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
1551 add_node_error(g, param_node->data.param_decl.type,
1552 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
1553 return g->builtin_types.entry_invalid;
1554 }
15551552 break;
15561553 }
15571554 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
test/cases/fn.zig+13
......@@ -119,3 +119,16 @@ test "assign inline fn to const variable" {
119119}
120120
121121inline fn inlineFn() void {}
122
123test "pass by non-copying value" {
124 assert(bar(Point{ .x = 1, .y = 2 }) == 3);
125}
126
127const Point = struct {
128 x: i32,
129 y: i32,
130};
131
132fn bar(pt: Point) i32 {
133 return pt.x + pt.y;
134}
test/compile_errors.zig-23
......@@ -2573,15 +2573,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25732573 break :x tc;
25742574 });
25752575
2576 cases.add(
2577 "pass non-copyable type by value to function",
2578 \\const Point = struct { x: i32, y: i32, };
2579 \\fn foo(p: Point) void { }
2580 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2581 ,
2582 ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value",
2583 );
2584
25852576 cases.add(
25862577 "implicit cast from array to mutable slice",
25872578 \\var global_array: [10]i32 = undefined;
......@@ -4066,20 +4057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40664057 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
40674058 );
40684059
4069 cases.add(
4070 "self-referencing function pointer field",
4071 \\const S = struct {
4072 \\ f: fn(_: S) void,
4073 \\};
4074 \\fn f(_: S) void {
4075 \\}
4076 \\export fn entry() void {
4077 \\ var _ = S { .f = f };
4078 \\}
4079 ,
4080 ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value",
4081 );
4082
40834060 cases.add(
40844061 "taking offset of void field in struct",
40854062 \\const Empty = struct {