From 1f602fe8c5b3dea9f00f96e70dad73ebce405b49 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 5 Dec 2019 16:55:32 -0500 Subject: implement `@call` closes #3732 --- test/compile_errors.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/compile_errors.zig') diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d3d439aeaf..49c7094fb0 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,24 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "bad usage of @call", + \\export fn entry1() void { + \\ @call(.{}, foo, {}); + \\} + \\export fn entry2() void { + \\ comptime @call(.{ .modifier = .never_inline }, foo, .{}); + \\} + \\export fn entry3() void { + \\ comptime @call(.{ .modifier = .never_tail }, foo, .{}); + \\} + \\fn foo() void {} + , + "tmp.zig:2:21: error: expected tuple or struct, found 'void'", + "tmp.zig:5:58: error: unable to perform 'never_inline' call at compile-time", + "tmp.zig:8:56: error: unable to perform 'never_tail' call at compile-time", + ); + cases.add( \\export async fn foo() void {} , "tmp.zig:1:1: error: exported function cannot be async"); -- cgit v1.2.3 From ef83358eb6702e8541816817e98c3e7279033672 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 5 Dec 2019 17:37:29 -0500 Subject: remove `@noInlineCall` from zig --- doc/langref.html.in | 90 ++++++++++++++++++++++++++++++++++------------- lib/std/builtin.zig | 26 ++++++++++++++ lib/std/special/start.zig | 2 +- src/all_types.hpp | 1 - src/codegen.cpp | 1 - src/ir.cpp | 5 +-- test/compile_errors.zig | 23 ++++++------ 7 files changed, 106 insertions(+), 42 deletions(-) (limited to 'test/compile_errors.zig') diff --git a/doc/langref.html.in b/doc/langref.html.in index 446a201bbe..68aea860de 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6841,6 +6841,71 @@ async fn func(y: *i32) void {

{#header_close#} + {#header_open|@call#} +
{#syntax#}@call(options: std.builtin.CallOptions, function: var, args: var) var{#endsyntax#}
+

+ Calls a function, in the same way that invoking an expression with parentheses does: +

+ {#code_begin|test|call#} +const assert = @import("std").debug.assert; + +test "noinline function call" { + assert(@call(.{}, add, .{3, 9}) == 12); +} + +fn add(a: i32, b: i32) i32 { + return a + b; +} + {#code_end#} +

+ {#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The + {#syntax#}CallOptions{#endsyntax#} struct is reproduced here: +

+ {#code_begin|syntax#} +pub const CallOptions = struct { + modifier: Modifier = .auto, + stack: ?[]align(std.Target.stack_align) u8 = null, + + pub const Modifier = enum { + /// Equivalent to function call syntax. + auto, + + /// Asserts that the function call will not suspend. This allows a + /// non-async function to call an async function. + no_async, + + /// The function call will return an async function frame instead of + /// the function's result, which is expected to then be awaited. + /// This is equivalent to using the `async` keyword in front of function + /// call syntax. + async_call, + + /// Prevents tail call optimization. This guarantees that the return + /// address will point to the callsite, as opposed to the callsite's + /// callsite. If the call is otherwise required to be tail-called + /// or inlined, a compile error is emitted instead. + never_tail, + + /// Guarantees that the call will not be inlined. If the call is + /// otherwise required to be inlined, a compile error is emitted instead. + never_inline, + + /// Guarantees that the call will be generated with tail call optimization. + /// If this is not possible, a compile error is emitted instead. + always_tail, + + /// Guarantees that the call will inlined at the callsite. + /// If this is not possible, a compile error is emitted instead. + always_inline, + + /// Evaluates the call at compile-time. If the call cannot be completed at + /// compile-time, a compile error is emitted instead. + compile_time, + }; +}; + {#code_end#} + {#header_close#} + {#header_open|@cDefine#}
{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}

@@ -7445,7 +7510,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } Unlike a normal function call, however, {#syntax#}@inlineCall{#endsyntax#} guarantees that the call will be inlined. If the call cannot be inlined, a compile error is emitted.

- {#see_also|@noInlineCall#} + {#see_also|@call#} {#header_close#} {#header_open|@intCast#} @@ -7647,29 +7712,6 @@ fn targetFunction(x: i32) usize { {#code_end#} {#header_close#} - {#header_open|@noInlineCall#} -
{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}
-

- This calls a function, in the same way that invoking an expression with parentheses does: -

- {#code_begin|test#} -const assert = @import("std").debug.assert; - -test "noinline function call" { - assert(@noInlineCall(add, 3, 9) == 12); -} - -fn add(a: i32, b: i32) i32 { - return a + b; -} - {#code_end#} -

- Unlike a normal function call, however, {#syntax#}@noInlineCall{#endsyntax#} guarantees that the call - will not be inlined. If the call must be inlined, a compile error is emitted. -

- {#see_also|@inlineCall#} - {#header_close#} - {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 791d46bc34..8ac58ad2f4 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -379,13 +379,39 @@ pub const CallOptions = struct { stack: ?[]align(std.Target.stack_align) u8 = null, pub const Modifier = enum { + /// Equivalent to function call syntax. auto, + + /// Asserts that the function call will not suspend. This allows a + /// non-async function to call an async function. no_async, + + /// The function call will return an async function frame instead of + /// the function's result, which is expected to then be awaited. + /// This is equivalent to using the `async` keyword in front of function + /// call syntax. async_call, + + /// Prevents tail call optimization. This guarantees that the return + /// address will point to the callsite, as opposed to the callsite's + /// callsite. If the call is otherwise required to be tail-called + /// or inlined, a compile error is emitted instead. never_tail, + + /// Guarantees that the call will not be inlined. If the call is + /// otherwise required to be inlined, a compile error is emitted instead. never_inline, + + /// Guarantees that the call will be generated with tail call optimization. + /// If this is not possible, a compile error is emitted instead. always_tail, + + /// Guarantees that the call will inlined at the callsite. + /// If this is not possible, a compile error is emitted instead. always_inline, + + /// Evaluates the call at compile-time. If the call cannot be completed at + /// compile-time, a compile error is emitted instead. compile_time, }; }; diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index a93b01c290..8815e17a91 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -125,7 +125,7 @@ nakedcc fn _start() noreturn { } // If LLVM inlines stack variables into _start, they will overwrite // the command line argument data. - @noInlineCall(posixCallMainAndExit); + @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); } stdcallcc fn WinMainCRTStartup() noreturn { diff --git a/src/all_types.hpp b/src/all_types.hpp index c3d5793d7a..c350b04c9e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1701,7 +1701,6 @@ enum BuiltinFnId { BuiltinFnIdByteOffsetOf, BuiltinFnIdBitOffsetOf, BuiltinFnIdInlineCall, - BuiltinFnIdNoInlineCall, BuiltinFnIdNewStackCall, BuiltinFnIdAsyncCall, BuiltinFnIdTypeId, diff --git a/src/codegen.cpp b/src/codegen.cpp index 35ad039d68..c1d3dc3327 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8133,7 +8133,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdRound, "round", 2); create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); diff --git a/src/ir.cpp b/src/ir.cpp index 23114f9b50..e40fb854d6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6014,7 +6014,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); } case BuiltinFnIdInlineCall: - case BuiltinFnIdNoInlineCall: { if (node->data.fn_call_expr.params.length == 0) { add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0")); @@ -6035,11 +6034,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (args[i] == irb->codegen->invalid_instruction) return args[i]; } - CallModifier modifier = (builtin_fn->id == BuiltinFnIdInlineCall) ? - CallModifierAlwaysInline : CallModifierNeverInline; IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, - nullptr, modifier, false, nullptr, result_loc); + nullptr, CallModifierAlwaysInline, false, nullptr, result_loc); return ir_lval_wrap(irb, scope, call, lval, result_loc); } case BuiltinFnIdNewStackCall: diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 49c7094fb0..d1244188e6 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -13,11 +13,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry3() void { \\ comptime @call(.{ .modifier = .never_tail }, foo, .{}); \\} + \\export fn entry4() void { + \\ @call(.{ .modifier = .never_inline }, bar, .{}); + \\} + \\export fn entry5(c: bool) void { + \\ var baz = if (c) baz1 else baz2; + \\ @call(.{ .modifier = .compile_time }, baz, .{}); + \\} \\fn foo() void {} + \\inline fn bar() void {} + \\fn baz1() void {} + \\fn baz2() void {} , "tmp.zig:2:21: error: expected tuple or struct, found 'void'", "tmp.zig:5:58: error: unable to perform 'never_inline' call at compile-time", "tmp.zig:8:56: error: unable to perform 'never_tail' call at compile-time", + "tmp.zig:11:5: error: no-inline call of inline function", + "tmp.zig:15:43: error: unable to evaluate constant expression", ); cases.add( @@ -1945,17 +1957,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'", ); - cases.add( - "@noInlineCall on an inline function", - \\inline fn foo() void {} - \\ - \\export fn entry() void { - \\ @noInlineCall(foo); - \\} - , - "tmp.zig:4:5: error: no-inline call of inline function", - ); - cases.add( "comptime continue inside runtime catch", \\export fn entry(c: bool) void { -- cgit v1.2.3 From 71b7f4b47f69e9b3241e9d44554572258f5eb5b1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 Dec 2019 14:52:09 -0500 Subject: remove `@newStackCall` from zig --- doc/langref.html.in | 77 +++++++++++++++------------------ lib/std/special/start.zig | 2 +- src-self-hosted/ir.zig | 4 +- src/ir.cpp | 25 +++++++++-- test/compile_errors.zig | 10 ++--- test/stage1/behavior/new_stack_call.zig | 4 +- 6 files changed, 66 insertions(+), 56 deletions(-) (limited to 'test/compile_errors.zig') diff --git a/doc/langref.html.in b/doc/langref.html.in index e30f920af4..ba0aa7a778 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6904,6 +6904,41 @@ pub const CallOptions = struct { }; }; {#code_end#} + + {#header_open|Calling with a New Stack#} +

+ When the {#syntax#}stack{#endsyntax#} option is provided, instead of using the same stack as the caller, the function uses the provided stack. +

+ {#code_begin|test|new_stack_call#} +const std = @import("std"); +const assert = std.debug.assert; + +var new_stack_bytes: [1024]u8 align(16) = undefined; + +test "calling a function with a new stack" { + const arg = 1234; + + const a = @call(.{.stack = new_stack_bytes[0..512]}, targetFunction, .{arg}); + const b = @call(.{.stack = new_stack_bytes[512..]}, targetFunction, .{arg}); + _ = targetFunction(arg); + + assert(arg == 1234); + assert(a < b); +} + +fn targetFunction(x: i32) usize { + assert(x == 1234); + + var local_variable: i32 = 42; + const ptr = &local_variable; + ptr.* += 1; + + assert(local_variable == 43); + return @ptrToInt(ptr); +} + {#code_end#} + {#header_close#} + {#header_close#} {#header_open|@cDefine#} @@ -7649,48 +7684,6 @@ mem.set(u8, dest, c);{#endsyntax#}

{#header_close#} - {#header_open|@newStackCall#} -
{#syntax#}@newStackCall(new_stack: []align(target_stack_align) u8, function: var, args: ...) var{#endsyntax#}
-

- This calls a function, in the same way that invoking an expression with parentheses does. However, - instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#} - parameter. -

-

- The new stack must be aligned to {#syntax#}target_stack_align{#endsyntax#} bytes. This is a target-specific - number. A safe value that will work on all targets is {#syntax#}16{#endsyntax#}. This value can - also be obtained by using {#link|@sizeOf#} on the {#link|@Frame#} type of {#link|Async Functions#}. -

- {#code_begin|test#} -const std = @import("std"); -const assert = std.debug.assert; - -var new_stack_bytes: [1024]u8 align(16) = undefined; - -test "calling a function with a new stack" { - const arg = 1234; - - const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); - const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); - _ = targetFunction(arg); - - assert(arg == 1234); - assert(a < b); -} - -fn targetFunction(x: i32) usize { - assert(x == 1234); - - var local_variable: i32 = 42; - const ptr = &local_variable; - ptr.* += 1; - - assert(local_variable == 43); - return @ptrToInt(ptr); -} - {#code_end#} - {#header_close#} - {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index b00b5213a7..d10431da20 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -184,7 +184,7 @@ fn posixCallMainAndExit() noreturn { // 0, //) catch @panic("out of memory"); //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; - //std.os.exit(@newStackCall(new_stack, callMainWithArgs, argc, argv, envp)); + //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); } std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 8d1c32cefd..1d11d7969d 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -321,7 +321,7 @@ pub const Inst = struct { } const llvm_cc = llvm.CCallConv; - const fn_inline = llvm.FnInline.Auto; + const call_attr = llvm.CallAttr.Auto; return llvm.BuildCall( ofile.builder, @@ -329,7 +329,7 @@ pub const Inst = struct { args.ptr, @intCast(c_uint, args.len), llvm_cc, - fn_inline, + call_attr, "", ) orelse error.OutOfMemory; } diff --git a/src/ir.cpp b/src/ir.cpp index 6e0e321300..e6978eae77 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13358,6 +13358,15 @@ static IrInstruction *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst return ir_get_deref(ira, source_instr, field_ptr, nullptr); } +static IrInstruction *ir_analyze_optional_value_payload_value(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *optional_operand, bool safety_check_on) +{ + IrInstruction *opt_ptr = ir_get_ref(ira, source_instr, optional_operand, true, false); + IrInstruction *payload_ptr = ir_analyze_unwrap_optional_payload(ira, source_instr, opt_ptr, + safety_check_on, false); + return ir_get_deref(ira, source_instr, payload_ptr, nullptr); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, ZigType *wanted_type, IrInstruction *value) { @@ -17521,7 +17530,7 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstruction *so arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr) { ir_add_error(ira, source_instr, - buf_sprintf("target arch '%s' does not support @newStackCall", + buf_sprintf("target arch '%s' does not support calling with a new stack", target_arch_name(ira->codegen->zig_target->arch))); } @@ -18223,13 +18232,21 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack")); ir_assert(stack_field != nullptr, source_instr); - IrInstruction *stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field); - IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, stack); + IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field); + if (type_is_invalid(opt_stack->value->type)) + return ira->codegen->invalid_instruction; + IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack); bool stack_is_non_null; if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null)) return ira->codegen->invalid_instruction; - if (!stack_is_non_null) + IrInstruction *stack; + if (stack_is_non_null) { + stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false); + if (type_is_invalid(stack->value->type)) + return ira->codegen->invalid_instruction; + } else { stack = nullptr; + } return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr, modifier, stack, false, args_ptr, args_len, nullptr, result_loc); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d1244188e6..9494879f71 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -26,8 +26,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn baz2() void {} , "tmp.zig:2:21: error: expected tuple or struct, found 'void'", - "tmp.zig:5:58: error: unable to perform 'never_inline' call at compile-time", - "tmp.zig:8:56: error: unable to perform 'never_tail' call at compile-time", + "tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time", + "tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time", "tmp.zig:11:5: error: no-inline call of inline function", "tmp.zig:15:43: error: unable to evaluate constant expression", ); @@ -44,13 +44,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.addCase(x: { - var tc = cases.create("@newStackCall on unsupported target", + var tc = cases.create("call with new stack on unsupported target", \\export fn entry() void { \\ var buf: [10]u8 align(16) = undefined; - \\ @newStackCall(&buf, foo); + \\ @call(.{.stack = &buf}, foo); \\} \\fn foo() void {} - , "tmp.zig:3:5: error: target arch 'wasm32' does not support @newStackCall"); + , "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack"); tc.target = tests.Target{ .Cross = tests.CrossTarget{ .arch = .wasm32, diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig index b057566d9c..69763a52c6 100644 --- a/test/stage1/behavior/new_stack_call.zig +++ b/test/stage1/behavior/new_stack_call.zig @@ -18,8 +18,8 @@ test "calling a function with a new stack" { const arg = 1234; - const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); - const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); + const a = @call(.{ .stack = new_stack_bytes[0..512] }, targetFunction, .{arg}); + const b = @call(.{ .stack = new_stack_bytes[512..] }, targetFunction, .{arg}); _ = targetFunction(arg); expect(arg == 1234); -- cgit v1.2.3 From 656cc33f8d49cb5e79cd3f9f8f56963747d43ed6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 Dec 2019 15:25:00 -0500 Subject: allow calling with a new stack to regress a bit Calling with a new stack, with a runtime-known stack pointer (e.g. not a global variable) is regressed with this branch. It is now a compile-error, due to the Runtime Hint system not being smart enough to mix a compile-time modifier field with a runtime stack field. I'm OK with this regression because this feature is flawed (see #3268) and may be deleted from the language. --- doc/langref.html.in | 15 ++++----------- lib/std/builtin.zig | 14 ++++---------- src/all_types.hpp | 10 ++++++---- test/compile_errors.zig | 4 ++-- 4 files changed, 16 insertions(+), 27 deletions(-) (limited to 'test/compile_errors.zig') diff --git a/doc/langref.html.in b/doc/langref.html.in index ba0aa7a778..e7b28014bd 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6870,16 +6870,6 @@ pub const CallOptions = struct { /// Equivalent to function call syntax. auto, - /// Asserts that the function call will not suspend. This allows a - /// non-async function to call an async function. - no_async, - - /// The function call will return an async function frame instead of - /// the function's result, which is expected to then be awaited. - /// This is equivalent to using the `async` keyword in front of function - /// call syntax. - async_call, - /// Prevents tail call optimization. This guarantees that the return /// address will point to the callsite, as opposed to the callsite's /// callsite. If the call is otherwise required to be tail-called @@ -6890,6 +6880,10 @@ pub const CallOptions = struct { /// otherwise required to be inlined, a compile error is emitted instead. never_inline, + /// Asserts that the function call will not suspend. This allows a + /// non-async function to call an async function. + no_async, + /// Guarantees that the call will be generated with tail call optimization. /// If this is not possible, a compile error is emitted instead. always_tail, @@ -6938,7 +6932,6 @@ fn targetFunction(x: i32) usize { } {#code_end#} {#header_close#} - {#header_close#} {#header_open|@cDefine#} diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8ac58ad2f4..35188b61e3 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -382,16 +382,6 @@ pub const CallOptions = struct { /// Equivalent to function call syntax. auto, - /// Asserts that the function call will not suspend. This allows a - /// non-async function to call an async function. - no_async, - - /// The function call will return an async function frame instead of - /// the function's result, which is expected to then be awaited. - /// This is equivalent to using the `async` keyword in front of function - /// call syntax. - async_call, - /// Prevents tail call optimization. This guarantees that the return /// address will point to the callsite, as opposed to the callsite's /// callsite. If the call is otherwise required to be tail-called @@ -402,6 +392,10 @@ pub const CallOptions = struct { /// otherwise required to be inlined, a compile error is emitted instead. never_inline, + /// Asserts that the function call will not suspend. This allows a + /// non-async function to call an async function. + no_async, + /// Guarantees that the call will be generated with tail call optimization. /// If this is not possible, a compile error is emitted instead. always_tail, diff --git a/src/all_types.hpp b/src/all_types.hpp index c8804ac273..a5b0804985 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -409,6 +409,9 @@ struct ZigValue { LLVMValueRef llvm_global; union { + // populated if special == ConstValSpecialLazy + LazyValue *x_lazy; + // populated if special == ConstValSpecialStatic BigInt x_bigint; BigFloat x_bigfloat; @@ -429,7 +432,6 @@ struct ZigValue { ConstPtrValue x_ptr; ConstArgTuple x_arg_tuple; Buf *x_enum_literal; - LazyValue *x_lazy; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -770,16 +772,16 @@ struct AstNodeUnwrapOptional { // Must be synchronized with std.builtin.CallOptions.Modifier enum CallModifier { CallModifierNone, - CallModifierNoAsync, - CallModifierAsync, CallModifierNeverTail, CallModifierNeverInline, + CallModifierNoAsync, CallModifierAlwaysTail, CallModifierAlwaysInline, CallModifierCompileTime, - // This is an additional tag in the compiler, but not exposed in the std lib. + // These are additional tags in the compiler, but not exposed in the std lib. CallModifierBuiltin, + CallModifierAsync, }; struct AstNodeFnCallExpr { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9494879f71..13e666f49e 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -45,9 +45,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.addCase(x: { var tc = cases.create("call with new stack on unsupported target", + \\var buf: [10]u8 align(16) = undefined; \\export fn entry() void { - \\ var buf: [10]u8 align(16) = undefined; - \\ @call(.{.stack = &buf}, foo); + \\ @call(.{.stack = &buf}, foo, .{}); \\} \\fn foo() void {} , "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack"); -- cgit v1.2.3