Commit 6b9dc82fa5

Tadeo Kondrak <me@tadeo.ca>
2020-10-08 01:38:42
stage1: Compile error instead of falling back to C for unsupported cc
1 parent 2b7781d
Changed files (2)
src/stage1/analyze.cpp
@@ -1880,6 +1880,58 @@ ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) {
     return err_set_type;
 }
 
+// Sync this with get_llvm_cc in codegen.cpp
+static Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc) {
+    Error ret = ErrorNone;
+    const char *allowed_platforms = nullptr;
+    switch (cc) {
+        case CallingConventionUnspecified:
+        case CallingConventionC:
+        case CallingConventionNaked:
+        case CallingConventionAsync:
+            break;
+        case CallingConventionInterrupt:
+            if (g->zig_target->arch != ZigLLVM_x86
+                && g->zig_target->arch != ZigLLVM_x86_64
+                && g->zig_target->arch != ZigLLVM_avr
+                && g->zig_target->arch != ZigLLVM_msp430)
+            {
+                allowed_platforms = "x86, x86_64, AVR, and MS430";
+            }
+            break;
+        case CallingConventionSignal:
+            if (g->zig_target->arch != ZigLLVM_avr)
+                allowed_platforms = "AVR";
+            break;
+        case CallingConventionStdcall:
+        case CallingConventionFastcall:
+        case CallingConventionThiscall:
+            if (g->zig_target->arch != ZigLLVM_x86)
+                allowed_platforms = "x86";
+            break;
+        case CallingConventionVectorcall:
+            if (g->zig_target->arch != ZigLLVM_x86
+                && !(target_is_arm(g->zig_target) && target_arch_pointer_bit_width(g->zig_target->arch) == 64))
+            {
+                allowed_platforms = "x86 and AArch64";
+            }
+            break;
+        case CallingConventionAPCS:
+        case CallingConventionAAPCS:
+        case CallingConventionAAPCSVFP:
+            if (!target_is_arm(g->zig_target))
+                allowed_platforms = "ARM";
+    }
+    if (allowed_platforms != nullptr) {
+        add_node_error(g, source_node, buf_sprintf(
+            "callconv '%s' is only available on %s, not %s",
+            calling_convention_name(cc), allowed_platforms,
+            target_arch_name(g->zig_target->arch)));
+        ret = ErrorSemanticAnalyzeFail;
+    }
+    return ret;
+}
+
 static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, ZigFn *fn_entry,
         CallingConvention cc)
 {
@@ -2014,6 +2066,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
         fn_entry->align_bytes = fn_type_id.alignment;
     }
 
+    if ((err = emit_error_unless_callconv_allowed_for_target(g, proto_node, cc)))
+        return g->builtin_types.entry_invalid;
+
     if (fn_proto->return_anytype_token != nullptr) {
         if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
             add_node_error(g, fn_proto->return_type,
src/stage1/codegen.cpp
@@ -155,6 +155,7 @@ static const char *get_mangled_name(CodeGen *g, const char *original_name) {
     }
 }
 
+// Sync this with emit_error_unless_callconv_allowed_for_target in analyze.cpp
 static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
     switch (cc) {
         case CallingConventionUnspecified:
@@ -164,38 +165,32 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
         case CallingConventionNaked:
             zig_unreachable();
         case CallingConventionStdcall:
-            if (g->zig_target->arch == ZigLLVM_x86)
-                return ZigLLVM_X86_StdCall;
-            return ZigLLVM_C;
+            assert(g->zig_target->arch == ZigLLVM_x86);
+            return ZigLLVM_X86_StdCall;
         case CallingConventionFastcall:
-            if (g->zig_target->arch == ZigLLVM_x86)
-                return ZigLLVM_X86_FastCall;
-            return ZigLLVM_C;
+            assert(g->zig_target->arch == ZigLLVM_x86);
+            return ZigLLVM_X86_FastCall;
         case CallingConventionVectorcall:
             if (g->zig_target->arch == ZigLLVM_x86)
                 return ZigLLVM_X86_VectorCall;
             if (target_is_arm(g->zig_target) &&
                 target_arch_pointer_bit_width(g->zig_target->arch) == 64)
                 return ZigLLVM_AArch64_VectorCall;
-            return ZigLLVM_C;
+            zig_unreachable();
         case CallingConventionThiscall:
-            if (g->zig_target->arch == ZigLLVM_x86)
-                return ZigLLVM_X86_ThisCall;
-            return ZigLLVM_C;
+            assert(g->zig_target->arch == ZigLLVM_x86);
+            return ZigLLVM_X86_ThisCall;
         case CallingConventionAsync:
             return ZigLLVM_Fast;
         case CallingConventionAPCS:
-            if (target_is_arm(g->zig_target))
-                return ZigLLVM_ARM_APCS;
-            return ZigLLVM_C;
+            assert(target_is_arm(g->zig_target));
+            return ZigLLVM_ARM_APCS;
         case CallingConventionAAPCS:
-            if (target_is_arm(g->zig_target))
-                return ZigLLVM_ARM_AAPCS;
-            return ZigLLVM_C;
+            assert(target_is_arm(g->zig_target));
+            return ZigLLVM_ARM_AAPCS;
         case CallingConventionAAPCSVFP:
-            if (target_is_arm(g->zig_target))
-                return ZigLLVM_ARM_AAPCS_VFP;
-            return ZigLLVM_C;
+            assert(target_is_arm(g->zig_target));
+            return ZigLLVM_ARM_AAPCS_VFP;
         case CallingConventionInterrupt:
             if (g->zig_target->arch == ZigLLVM_x86 ||
                 g->zig_target->arch == ZigLLVM_x86_64)
@@ -204,11 +199,10 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
                 return ZigLLVM_AVR_INTR;
             if (g->zig_target->arch == ZigLLVM_msp430)
                 return ZigLLVM_MSP430_INTR;
-            return ZigLLVM_C;
+            zig_unreachable();
         case CallingConventionSignal:
-            if (g->zig_target->arch == ZigLLVM_avr)
-                return ZigLLVM_AVR_SIGNAL;
-            return ZigLLVM_C;
+            assert(g->zig_target->arch == ZigLLVM_avr);
+            return ZigLLVM_AVR_SIGNAL;
     }
     zig_unreachable();
 }