Ensure all previous test cases are still passing, as well as add some basic tests for now for testing pointers to the stack. This means we can start implementing wasm's C ABI found at: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md We also simplified the block logic by always using 'void' block types and instead writing the value to a local, which can then be referenced by continues instructions, as done currently by AIR. Besides this, we also no longer need to insert blocks at an offset, as we simply write the saved temporary after we create the block.
779 lines
20 KiB
Zig
779 lines
20 KiB
Zig
const std = @import("std");
|
|
const TestContext = @import("../../src/test.zig").TestContext;
|
|
|
|
const wasi = std.zig.CrossTarget{
|
|
.cpu_arch = .wasm32,
|
|
.os_tag = .wasi,
|
|
};
|
|
|
|
pub fn addCases(ctx: *TestContext) !void {
|
|
{
|
|
var case = ctx.exe("wasm function calls", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ foo();
|
|
\\ bar();
|
|
\\ return 42;
|
|
\\}
|
|
\\fn foo() void {
|
|
\\ bar();
|
|
\\ bar();
|
|
\\}
|
|
\\fn bar() void {}
|
|
,
|
|
"42\n",
|
|
);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i64 {
|
|
\\ bar();
|
|
\\ foo();
|
|
\\ foo();
|
|
\\ bar();
|
|
\\ foo();
|
|
\\ bar();
|
|
\\ return 42;
|
|
\\}
|
|
\\fn foo() void {
|
|
\\ bar();
|
|
\\}
|
|
\\fn bar() void {}
|
|
,
|
|
"42\n",
|
|
);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() f32 {
|
|
\\ bar();
|
|
\\ foo();
|
|
\\ return 42.0;
|
|
\\}
|
|
\\fn foo() void {
|
|
\\ bar();
|
|
\\ bar();
|
|
\\ bar();
|
|
\\}
|
|
\\fn bar() void {}
|
|
,
|
|
"42\n",
|
|
);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ foo(10, 20);
|
|
\\ return 5;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) void { _ = x; _ = y; }
|
|
, "5\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm locals", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ var y: f32 = 42.0;
|
|
\\ var x: u32 = 10;
|
|
\\ if (false) {
|
|
\\ y;
|
|
\\ x;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ var y: f32 = 42.0;
|
|
\\ _ = y;
|
|
\\ var x: u32 = 10;
|
|
\\ foo(i, x);
|
|
\\ i = x;
|
|
\\ return i;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) void {
|
|
\\ _ = y;
|
|
\\ var i: u32 = 10;
|
|
\\ i = x;
|
|
\\}
|
|
, "10\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm binary operands", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i += 20;
|
|
\\ return i;
|
|
\\}
|
|
, "25\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i32 = 2147483647;
|
|
\\ return i +% 1;
|
|
\\}
|
|
, "-2147483648\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i4 = 7;
|
|
\\ return i +% 1;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u8 = 255;
|
|
\\ return i +% 1;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i += 20;
|
|
\\ var result: u32 = foo(i, 10);
|
|
\\ return result;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) u32 {
|
|
\\ return x + y;
|
|
\\}
|
|
, "35\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 20;
|
|
\\ i -= 5;
|
|
\\ return i;
|
|
\\}
|
|
, "15\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i32 = -2147483648;
|
|
\\ return i -% 1;
|
|
\\}
|
|
, "2147483647\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i7 = -64;
|
|
\\ return i -% 1;
|
|
\\}
|
|
, "63\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u4 = 0;
|
|
\\ return i -% 1;
|
|
\\}
|
|
, "15\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i -= 3;
|
|
\\ var result: u32 = foo(i, 10);
|
|
\\ return result;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) u32 {
|
|
\\ return y - x;
|
|
\\}
|
|
, "8\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i *= 7;
|
|
\\ var result: u32 = foo(i, 10);
|
|
\\ return result;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) u32 {
|
|
\\ return x * y;
|
|
\\}
|
|
, "350\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i32 = 2147483647;
|
|
\\ return i *% 2;
|
|
\\}
|
|
, "-2\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u3 = 3;
|
|
\\ return i *% 3;
|
|
\\}
|
|
, "1\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() i32 {
|
|
\\ var i: i4 = 3;
|
|
\\ return i *% 3;
|
|
\\}
|
|
, "1\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 352;
|
|
\\ i /= 7; // i = 50
|
|
\\ var result: u32 = foo(i, 7);
|
|
\\ return result;
|
|
\\}
|
|
\\fn foo(x: u32, y: u32) u32 {
|
|
\\ return x / y;
|
|
\\}
|
|
, "7\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i &= 6;
|
|
\\ return i;
|
|
\\}
|
|
, "4\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i |= 6;
|
|
\\ return i;
|
|
\\}
|
|
, "7\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ i ^= 6;
|
|
\\ return i;
|
|
\\}
|
|
, "3\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = false;
|
|
\\ b = b or false;
|
|
\\ return b;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = true;
|
|
\\ b = b or false;
|
|
\\ return b;
|
|
\\}
|
|
, "1\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = false;
|
|
\\ b = b or true;
|
|
\\ return b;
|
|
\\}
|
|
, "1\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = true;
|
|
\\ b = b or true;
|
|
\\ return b;
|
|
\\}
|
|
, "1\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = false;
|
|
\\ b = b and false;
|
|
\\ return b;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = true;
|
|
\\ b = b and false;
|
|
\\ return b;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = false;
|
|
\\ b = b and true;
|
|
\\ return b;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() bool {
|
|
\\ var b: bool = true;
|
|
\\ b = b and true;
|
|
\\ return b;
|
|
\\}
|
|
, "1\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm conditions", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ if (i > @as(u32, 4)) {
|
|
\\ i += 10;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "15\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ if (i < @as(u32, 4)) {
|
|
\\ i += 10;
|
|
\\ } else {
|
|
\\ i = 2;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "2\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 5;
|
|
\\ if (i < @as(u32, 4)) {
|
|
\\ i += 10;
|
|
\\ } else if(i == @as(u32, 5)) {
|
|
\\ i = 20;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "20\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 11;
|
|
\\ if (i < @as(u32, 4)) {
|
|
\\ i += 10;
|
|
\\ } else {
|
|
\\ if (i > @as(u32, 10)) {
|
|
\\ i += 20;
|
|
\\ } else {
|
|
\\ i = 20;
|
|
\\ }
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "31\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() void {
|
|
\\ assert(foo(true) != @as(i32, 30));
|
|
\\}
|
|
\\
|
|
\\fn assert(ok: bool) void {
|
|
\\ if (!ok) unreachable;
|
|
\\}
|
|
\\
|
|
\\fn foo(ok: bool) i32 {
|
|
\\ const x = if(ok) @as(i32, 20) else @as(i32, 10);
|
|
\\ return x;
|
|
\\}
|
|
, "");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() void {
|
|
\\ assert(foo(false) == @as(i32, 20));
|
|
\\ assert(foo(true) == @as(i32, 30));
|
|
\\}
|
|
\\
|
|
\\fn assert(ok: bool) void {
|
|
\\ if (!ok) unreachable;
|
|
\\}
|
|
\\
|
|
\\fn foo(ok: bool) i32 {
|
|
\\ const val: i32 = blk: {
|
|
\\ var x: i32 = 1;
|
|
\\ if (!ok) break :blk x + @as(i32, 9);
|
|
\\ break :blk x + @as(i32, 19);
|
|
\\ };
|
|
\\ return val + 10;
|
|
\\}
|
|
, "");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm while loops", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 0;
|
|
\\ while(i < @as(u32, 5)){
|
|
\\ i += 1;
|
|
\\ }
|
|
\\
|
|
\\ return i;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 0;
|
|
\\ while(i < @as(u32, 10)){
|
|
\\ var x: u32 = 1;
|
|
\\ i += x;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "10\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var i: u32 = 0;
|
|
\\ while(i < @as(u32, 10)){
|
|
\\ var x: u32 = 1;
|
|
\\ i += x;
|
|
\\ if (i == @as(u32, 5)) break;
|
|
\\ }
|
|
\\ return i;
|
|
\\}
|
|
, "5\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm enum values", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\const Number = enum { One, Two, Three };
|
|
\\
|
|
\\pub export fn _start() i32 {
|
|
\\ var number1 = Number.One;
|
|
\\ var number2: Number = .Two;
|
|
\\ if (false) {
|
|
\\ number1;
|
|
\\ number2;
|
|
\\ }
|
|
\\ const number3 = @intToEnum(Number, 2);
|
|
\\
|
|
\\ return @enumToInt(number3);
|
|
\\}
|
|
, "2\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const Number = enum { One, Two, Three };
|
|
\\
|
|
\\pub export fn _start() i32 {
|
|
\\ var number1 = Number.One;
|
|
\\ var number2: Number = .Two;
|
|
\\ const number3 = @intToEnum(Number, 2);
|
|
\\ if (number1 == number2) return 1;
|
|
\\ if (number2 == number3) return 1;
|
|
\\ if (@enumToInt(number1) != 0) return 1;
|
|
\\ if (@enumToInt(number2) != 1) return 1;
|
|
\\ if (@enumToInt(number3) != 2) return 1;
|
|
\\ var x: Number = .Two;
|
|
\\ if (number2 != x) return 1;
|
|
\\
|
|
\\ return @enumToInt(number3);
|
|
\\}
|
|
, "2\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm structs", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\const Example = struct { x: u32 };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var example: Example = .{ .x = 5 };
|
|
\\ return example.x;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const Example = struct { x: u32 };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var example: Example = .{ .x = 5 };
|
|
\\ example.x = 10;
|
|
\\ return example.x;
|
|
\\}
|
|
, "10\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const Example = struct { x: u32, y: u32 };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var example: Example = .{ .x = 5, .y = 10 };
|
|
\\ return example.y + example.x;
|
|
\\}
|
|
, "15\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const Example = struct { x: u32, y: u32 };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var example: Example = .{ .x = 5, .y = 10 };
|
|
\\ var example2: Example = .{ .x = 10, .y = 20 };
|
|
\\
|
|
\\ example = example2;
|
|
\\ return example.y + example.x;
|
|
\\}
|
|
, "30\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const Example = struct { x: u32, y: u32 };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var example: Example = .{ .x = 5, .y = 10 };
|
|
\\
|
|
\\ example = .{ .x = 10, .y = 20 };
|
|
\\ return example.y + example.x;
|
|
\\}
|
|
, "30\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm switch", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var val: u32 = 1;
|
|
\\ var a: u32 = switch (val) {
|
|
\\ 0, 1 => 2,
|
|
\\ 2 => 3,
|
|
\\ 3 => 4,
|
|
\\ else => 5,
|
|
\\ };
|
|
\\
|
|
\\ return a;
|
|
\\}
|
|
, "2\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var val: u32 = 2;
|
|
\\ var a: u32 = switch (val) {
|
|
\\ 0, 1 => 2,
|
|
\\ 2 => 3,
|
|
\\ 3 => 4,
|
|
\\ else => 5,
|
|
\\ };
|
|
\\
|
|
\\ return a;
|
|
\\}
|
|
, "3\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var val: u32 = 10;
|
|
\\ var a: u32 = switch (val) {
|
|
\\ 0, 1 => 2,
|
|
\\ 2 => 3,
|
|
\\ 3 => 4,
|
|
\\ else => 5,
|
|
\\ };
|
|
\\
|
|
\\ return a;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\const MyEnum = enum { One, Two, Three };
|
|
\\
|
|
\\pub export fn _start() u32 {
|
|
\\ var val: MyEnum = .Two;
|
|
\\ var a: u32 = switch (val) {
|
|
\\ .One => 1,
|
|
\\ .Two => 2,
|
|
\\ .Three => 3,
|
|
\\ };
|
|
\\
|
|
\\ return a;
|
|
\\}
|
|
, "2\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm error unions", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() void {
|
|
\\ var e1 = error.Foo;
|
|
\\ var e2 = error.Bar;
|
|
\\ assert(e1 != e2);
|
|
\\ assert(e1 == error.Foo);
|
|
\\ assert(e2 == error.Bar);
|
|
\\}
|
|
\\
|
|
\\fn assert(b: bool) void {
|
|
\\ if (!b) unreachable;
|
|
\\}
|
|
, "");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var e: anyerror!u32 = 5;
|
|
\\ const i = e catch 10;
|
|
\\ return i;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var e: anyerror!u32 = error.Foo;
|
|
\\ const i = e catch 10;
|
|
\\ return i;
|
|
\\}
|
|
, "10\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var e = foo();
|
|
\\ const i = e catch 69;
|
|
\\ return i;
|
|
\\}
|
|
\\
|
|
\\fn foo() anyerror!u32 {
|
|
\\ return 5;
|
|
\\}
|
|
, "5\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm error union part 2", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var e = foo();
|
|
\\ const i = e catch 69;
|
|
\\ return i;
|
|
\\}
|
|
\\
|
|
\\fn foo() anyerror!u32 {
|
|
\\ return error.Bruh;
|
|
\\}
|
|
, "69\n");
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var e = foo();
|
|
\\ const i = e catch 42;
|
|
\\ return i;
|
|
\\}
|
|
\\
|
|
\\fn foo() anyerror!u32 {
|
|
\\ return error.Dab;
|
|
\\}
|
|
, "42\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm integer widening", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u64 {
|
|
\\ var x: u32 = 5;
|
|
\\ return x;
|
|
\\}
|
|
, "5\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm optionals", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: ?u32 = 5;
|
|
\\ var y: u32 = 0;
|
|
\\ if (x) |val| {
|
|
\\ y = val;
|
|
\\ }
|
|
\\ return y;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: ?u32 = null;
|
|
\\ var y: u32 = 0;
|
|
\\ if (x) |val| {
|
|
\\ y = val;
|
|
\\ }
|
|
\\ return y;
|
|
\\}
|
|
, "0\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: ?u32 = 5;
|
|
\\ return x.?;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: u32 = 5;
|
|
\\ var y: ?u32 = x;
|
|
\\ return y.?;
|
|
\\}
|
|
, "5\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var val: ?u32 = 5;
|
|
\\ while (val) |*v| {
|
|
\\ v.* -= 1;
|
|
\\ if (v.* == 2) {
|
|
\\ val = null;
|
|
\\ }
|
|
\\ }
|
|
\\ return 0;
|
|
\\}
|
|
, "0\n");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("wasm pointers", wasi);
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: u32 = 0;
|
|
\\
|
|
\\ foo(&x);
|
|
\\ return x;
|
|
\\}
|
|
\\
|
|
\\fn foo(x: *u32)void {
|
|
\\ x.* = 2;
|
|
\\}
|
|
, "2\n");
|
|
|
|
case.addCompareOutput(
|
|
\\pub export fn _start() u32 {
|
|
\\ var x: u32 = 0;
|
|
\\
|
|
\\ foo(&x);
|
|
\\ bar(&x);
|
|
\\ return x;
|
|
\\}
|
|
\\
|
|
\\fn foo(x: *u32)void {
|
|
\\ x.* = 2;
|
|
\\}
|
|
\\
|
|
\\fn bar(x: *u32) void {
|
|
\\ x.* += 2;
|
|
\\}
|
|
, "4\n");
|
|
}
|
|
}
|