remove `@noInlineCall` from zig

master
Andrew Kelley 2019-12-05 17:37:29 -05:00
parent 1f602fe8c5
commit ef83358eb6
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
7 changed files with 106 additions and 42 deletions

View File

@ -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>

View File

@ -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,
}; };
}; };

View File

@ -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 {

View File

@ -1701,7 +1701,6 @@ enum BuiltinFnId {
BuiltinFnIdByteOffsetOf, BuiltinFnIdByteOffsetOf,
BuiltinFnIdBitOffsetOf, BuiltinFnIdBitOffsetOf,
BuiltinFnIdInlineCall, BuiltinFnIdInlineCall,
BuiltinFnIdNoInlineCall,
BuiltinFnIdNewStackCall, BuiltinFnIdNewStackCall,
BuiltinFnIdAsyncCall, BuiltinFnIdAsyncCall,
BuiltinFnIdTypeId, BuiltinFnIdTypeId,

View File

@ -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);

View File

@ -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:

View File

@ -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 {