Commit 59b3dc8907
Changed files (4)
doc/langref.html.in
@@ -2797,39 +2797,30 @@ fn foo() void { }
{#code_end#}
{#header_open|Pass-by-value Parameters#}
<p>
- In Zig, structs, unions, and enums with payloads cannot be passed by value
- to a function.
+ In Zig, structs, unions, and enums with payloads can be passed directly to a function:
</p>
- {#code_begin|test_err|not copyable; cannot pass by value#}
-const Foo = struct {
+ {#code_begin|test#}
+const Point = struct {
x: i32,
+ y: i32,
};
-fn bar(foo: Foo) void {}
-
-test "pass aggregate type by value to function" {
- bar(Foo {.x = 12,});
+fn foo(point: Point) i32 {
+ return point.x + point.y;
}
- {#code_end#}
- <p>
- Instead, one must use <code>*const</code>. Zig allows implicitly casting something
- to a const pointer to it:
- </p>
- {#code_begin|test#}
-const Foo = struct {
- x: i32,
-};
-fn bar(foo: *const Foo) void {}
+const assert = @import("std").debug.assert;
-test "implicitly cast to const pointer" {
- bar(Foo {.x = 12,});
+test "pass aggregate type by non-copy value to function" {
+ assert(foo(Point{ .x = 1, .y = 2 }) == 3);
}
{#code_end#}
<p>
- However,
- the C ABI does allow passing structs and unions by value. So functions which
- use the C calling convention may pass structs and unions by value.
+ In this case, the value may be passed by reference, or by value, whichever way
+ Zig decides will be faster.
+ </p>
+ <p>
+ For extern functions, Zig follows the C ABI for passing structs and unions by value.
</p>
{#header_close#}
{#header_open|Function Reflection#}
src/analyze.cpp
@@ -1135,7 +1135,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
gen_param_info->src_index = i;
gen_param_info->gen_index = SIZE_MAX;
- type_ensure_zero_bits_known(g, type_entry);
+ ensure_complete_type(g, type_entry);
+ if (type_is_invalid(type_entry))
+ return g->builtin_types.entry_invalid;
+
if (type_has_bits(type_entry)) {
TypeTableEntry *gen_type;
if (handle_is_ptr(type_entry)) {
@@ -1546,12 +1549,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdPromise:
- ensure_complete_type(g, type_entry);
- if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
- add_node_error(g, param_node->data.param_decl.type,
- buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
- return g->builtin_types.entry_invalid;
- }
break;
}
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
test/cases/fn.zig
@@ -119,3 +119,16 @@ test "assign inline fn to const variable" {
}
inline fn inlineFn() void {}
+
+test "pass by non-copying value" {
+ assert(bar(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+const Point = struct {
+ x: i32,
+ y: i32,
+};
+
+fn bar(pt: Point) i32 {
+ return pt.x + pt.y;
+}
test/compile_errors.zig
@@ -2573,15 +2573,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
break :x tc;
});
- cases.add(
- "pass non-copyable type by value to function",
- \\const Point = struct { x: i32, y: i32, };
- \\fn foo(p: Point) void { }
- \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
- ,
- ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value",
- );
-
cases.add(
"implicit cast from array to mutable slice",
\\var global_array: [10]i32 = undefined;
@@ -4066,20 +4057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
);
- cases.add(
- "self-referencing function pointer field",
- \\const S = struct {
- \\ f: fn(_: S) void,
- \\};
- \\fn f(_: S) void {
- \\}
- \\export fn entry() void {
- \\ var _ = S { .f = f };
- \\}
- ,
- ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value",
- );
-
cases.add(
"taking offset of void field in struct",
\\const Empty = struct {