Commit ef83358eb6

Andrew Kelley <andrew@ziglang.org>
2019-12-05 23:37:29
remove `@noInlineCall` from zig
1 parent 1f602fe
doc/langref.html.in
@@ -6841,6 +6841,71 @@ async fn func(y: *i32) void {
       </p>
       {#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#}
       <pre>{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}</pre>
       <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
       will be inlined. If the call cannot be inlined, a compile error is emitted.
       </p>
-      {#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#}
-      <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#}
       <pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
       <p>
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 {
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,
     };
 };
src/all_types.hpp
@@ -1701,7 +1701,6 @@ enum BuiltinFnId {
     BuiltinFnIdByteOffsetOf,
     BuiltinFnIdBitOffsetOf,
     BuiltinFnIdInlineCall,
-    BuiltinFnIdNoInlineCall,
     BuiltinFnIdNewStackCall,
     BuiltinFnIdAsyncCall,
     BuiltinFnIdTypeId,
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);
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:
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 {