remove `@noInlineCall` from zig
parent
1f602fe8c5
commit
ef83358eb6
|
@ -6841,6 +6841,71 @@ async fn func(y: *i32) void {
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@call#}
|
||||||
|
<pre>{#syntax#}@call(options: std.builtin.CallOptions, function: var, args: var) var{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Calls a function, in the same way that invoking an expression with parentheses does:
|
||||||
|
</p>
|
||||||
|
{#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#}
|
||||||
|
<p>
|
||||||
|
{#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The
|
||||||
|
{#syntax#}CallOptions{#endsyntax#} struct is reproduced here:
|
||||||
|
</p>
|
||||||
|
{#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#}
|
{#header_open|@cDefine#}
|
||||||
<pre>{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}</pre>
|
<pre>{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
|
@ -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
|
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.
|
will be inlined. If the call cannot be inlined, a compile error is emitted.
|
||||||
</p>
|
</p>
|
||||||
{#see_also|@noInlineCall#}
|
{#see_also|@call#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@intCast#}
|
{#header_open|@intCast#}
|
||||||
|
@ -7647,29 +7712,6 @@ fn targetFunction(x: i32) usize {
|
||||||
{#code_end#}
|
{#code_end#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@noInlineCall#}
|
|
||||||
<pre>{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}</pre>
|
|
||||||
<p>
|
|
||||||
This calls a function, in the same way that invoking an expression with parentheses does:
|
|
||||||
</p>
|
|
||||||
{#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#}
|
|
||||||
<p>
|
|
||||||
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.
|
|
||||||
</p>
|
|
||||||
{#see_also|@inlineCall#}
|
|
||||||
{#header_close#}
|
|
||||||
|
|
||||||
{#header_open|@OpaqueType#}
|
{#header_open|@OpaqueType#}
|
||||||
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
|
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -379,13 +379,39 @@ pub const CallOptions = struct {
|
||||||
stack: ?[]align(std.Target.stack_align) u8 = null,
|
stack: ?[]align(std.Target.stack_align) u8 = null,
|
||||||
|
|
||||||
pub const Modifier = enum {
|
pub const Modifier = enum {
|
||||||
|
/// Equivalent to function call syntax.
|
||||||
auto,
|
auto,
|
||||||
|
|
||||||
|
/// Asserts that the function call will not suspend. This allows a
|
||||||
|
/// non-async function to call an async function.
|
||||||
no_async,
|
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,
|
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,
|
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,
|
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,
|
always_tail,
|
||||||
|
|
||||||
|
/// Guarantees that the call will inlined at the callsite.
|
||||||
|
/// If this is not possible, a compile error is emitted instead.
|
||||||
always_inline,
|
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,
|
compile_time,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -125,7 +125,7 @@ nakedcc fn _start() noreturn {
|
||||||
}
|
}
|
||||||
// If LLVM inlines stack variables into _start, they will overwrite
|
// If LLVM inlines stack variables into _start, they will overwrite
|
||||||
// the command line argument data.
|
// the command line argument data.
|
||||||
@noInlineCall(posixCallMainAndExit);
|
@call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
stdcallcc fn WinMainCRTStartup() noreturn {
|
stdcallcc fn WinMainCRTStartup() noreturn {
|
||||||
|
|
|
@ -1701,7 +1701,6 @@ enum BuiltinFnId {
|
||||||
BuiltinFnIdByteOffsetOf,
|
BuiltinFnIdByteOffsetOf,
|
||||||
BuiltinFnIdBitOffsetOf,
|
BuiltinFnIdBitOffsetOf,
|
||||||
BuiltinFnIdInlineCall,
|
BuiltinFnIdInlineCall,
|
||||||
BuiltinFnIdNoInlineCall,
|
|
||||||
BuiltinFnIdNewStackCall,
|
BuiltinFnIdNewStackCall,
|
||||||
BuiltinFnIdAsyncCall,
|
BuiltinFnIdAsyncCall,
|
||||||
BuiltinFnIdTypeId,
|
BuiltinFnIdTypeId,
|
||||||
|
|
|
@ -8133,7 +8133,6 @@ static void define_builtin_fns(CodeGen *g) {
|
||||||
create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
|
create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
|
||||||
create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
|
create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
|
||||||
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
|
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, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
|
||||||
create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
|
create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
|
||||||
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
|
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
|
||||||
|
|
|
@ -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);
|
return ir_lval_wrap(irb, scope, offset_of, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdInlineCall:
|
case BuiltinFnIdInlineCall:
|
||||||
case BuiltinFnIdNoInlineCall:
|
|
||||||
{
|
{
|
||||||
if (node->data.fn_call_expr.params.length == 0) {
|
if (node->data.fn_call_expr.params.length == 0) {
|
||||||
add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 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)
|
if (args[i] == irb->codegen->invalid_instruction)
|
||||||
return args[i];
|
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,
|
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);
|
return ir_lval_wrap(irb, scope, call, lval, result_loc);
|
||||||
}
|
}
|
||||||
case BuiltinFnIdNewStackCall:
|
case BuiltinFnIdNewStackCall:
|
||||||
|
|
|
@ -13,11 +13,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||||
\\export fn entry3() void {
|
\\export fn entry3() void {
|
||||||
\\ comptime @call(.{ .modifier = .never_tail }, foo, .{});
|
\\ 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 {}
|
\\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: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: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: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(
|
cases.add(
|
||||||
|
@ -1945,17 +1957,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||||
"tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
|
"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(
|
cases.add(
|
||||||
"comptime continue inside runtime catch",
|
"comptime continue inside runtime catch",
|
||||||
\\export fn entry(c: bool) void {
|
\\export fn entry(c: bool) void {
|
||||||
|
|
Loading…
Reference in New Issue