Commit 65d3723968

Veikka Tuominen <git@vexu.eu>
2022-08-30 16:13:35
Sema: check that target supports tail calls
1 parent c558de6
Changed files (4)
lib/std/target.zig
@@ -1440,6 +1440,16 @@ pub const Target = struct {
         return !self.cpu.arch.isWasm();
     }
 
+    pub fn supportsTailCall(self: Target) bool {
+        switch (self.cpu.arch) {
+            .wasm32, .wasm64 => return wasm.featureSetHas(self.cpu.features, .tail_call),
+            // TODO these might not be true but LLVM doesn't seem to be able to handle them
+            .mips, .mipsel, .mips64, .mips64el => return false,
+            .powerpc, .powerpcle, .powerpc64, .powerpc64le => return false,
+            else => return true,
+        }
+    }
+
     pub const FloatAbi = enum {
         hard,
         soft,
src/Sema.zig
@@ -6160,6 +6160,10 @@ fn analyzeCall(
 }
 
 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
+    const target = sema.mod.getTarget();
+    if (!target.supportsTailCall()) {
+        return sema.fail(block, call_src, "unable to perform tail call: target does not support tail calls", .{});
+    }
     const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl);
     if (!func_ty.eql(func_decl.ty, sema.mod)) {
         return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
test/behavior/call.zig
@@ -270,6 +270,8 @@ test "forced tail call" {
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
 
+    if (comptime !builtin.target.supportsTailCall()) return error.SkipZigTest;
+
     const S = struct {
         fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 {
             if (n == 0) return a;
@@ -296,6 +298,8 @@ test "inline call preserves tail call" {
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
 
+    if (comptime !builtin.target.supportsTailCall()) return error.SkipZigTest;
+
     const max = std.math.maxInt(u16);
     const S = struct {
         var a: u16 = 0;
test/cases/taill_call_noreturn.zig
@@ -15,4 +15,4 @@ pub fn main() void {
 
 // run
 // backend=llvm
-// target=native
+// target=x86_64-linux,x86_64-macos,aarch64-linux,aarch64-macos