From 563d9ebfe597b313b265a5a30296c081fe35d87a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Dec 2019 21:52:06 +0100 Subject: Implement the callconv() annotation --- src/analyze.cpp | 154 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 55 deletions(-) (limited to 'src/analyze.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 8be25b7592..7e672e1936 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -919,24 +919,19 @@ ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) { const char *calling_convention_name(CallingConvention cc) { switch (cc) { - case CallingConventionUnspecified: return "undefined"; - case CallingConventionC: return "ccc"; - case CallingConventionCold: return "coldcc"; - case CallingConventionNaked: return "nakedcc"; - case CallingConventionStdcall: return "stdcallcc"; - case CallingConventionAsync: return "async"; - } - zig_unreachable(); -} - -static const char *calling_convention_fn_type_str(CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: return ""; - case CallingConventionC: return "extern "; - case CallingConventionCold: return "coldcc "; - case CallingConventionNaked: return "nakedcc "; - case CallingConventionStdcall: return "stdcallcc "; - case CallingConventionAsync: return "async "; + case CallingConventionUnspecified: return "Unspecified"; + case CallingConventionC: return "C"; + case CallingConventionCold: return "Cold"; + case CallingConventionNaked: return "Naked"; + case CallingConventionAsync: return "Async"; + case CallingConventionInterrupt: return "Interrupt"; + case CallingConventionSignal: return "Signal"; + case CallingConventionStdcall: return "Stdcall"; + case CallingConventionFastcall: return "Fastcall"; + case CallingConventionVectorcall: return "Vectorcall"; + case CallingConventionAPCS: return "Apcs"; + case CallingConventionAAPCS: return "Aapcs"; + case CallingConventionAAPCSVFP: return "Aapcsvfp"; } zig_unreachable(); } @@ -949,7 +944,14 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { case CallingConventionC: case CallingConventionCold: case CallingConventionNaked: + case CallingConventionInterrupt: + case CallingConventionSignal: case CallingConventionStdcall: + case CallingConventionFastcall: + case CallingConventionVectorcall: + case CallingConventionAPCS: + case CallingConventionAAPCS: + case CallingConventionAAPCSVFP: return false; } zig_unreachable(); @@ -1006,8 +1008,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { // populate the name of the type buf_resize(&fn_type->name, 0); - const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc); - buf_appendf(&fn_type->name, "%s", cc_str); + if (fn_type->data.fn.fn_type_id.cc == CallingConventionC) + buf_append_str(&fn_type->name, "extern "); buf_appendf(&fn_type->name, "fn("); for (size_t i = 0; i < fn_type_id->param_count; i += 1) { FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; @@ -1026,6 +1028,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (fn_type_id->alignment != 0) { buf_appendf(&fn_type->name, " align(%" PRIu32 ")", fn_type_id->alignment); } + if (fn_type_id->cc != CallingConventionUnspecified && fn_type_id->cc != CallingConventionC) { + buf_appendf(&fn_type->name, " callconv(%s)", calling_convention_name(fn_type_id->cc)); + } buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name)); // The fn_type is a pointer; not to be confused with the raw function type. @@ -1442,8 +1447,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); buf_resize(&fn_type->name, 0); - const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc); - buf_appendf(&fn_type->name, "%s", cc_str); + if (fn_type->data.fn.fn_type_id.cc == CallingConventionC) + buf_append_str(&fn_type->name, "extern "); buf_appendf(&fn_type->name, "fn("); size_t i = 0; for (; i < fn_type_id->next_param_index; i += 1) { @@ -1455,7 +1460,11 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { const char *comma_str = (i == 0) ? "" : ","; buf_appendf(&fn_type->name, "%svar", comma_str); } - buf_appendf(&fn_type->name, ")var"); + buf_append_str(&fn_type->name, ")"); + if (fn_type_id->cc != CallingConventionUnspecified && fn_type_id->cc != CallingConventionC) { + buf_appendf(&fn_type->name, " callconv(%s)", calling_convention_name(fn_type_id->cc)); + } + buf_append_str(&fn_type->name, " var"); fn_type->data.fn.fn_type_id = *fn_type_id; fn_type->data.fn.is_generic = true; @@ -1465,17 +1474,25 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { return fn_type; } -void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc) { +CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { + if (fn_proto->is_nakedcc) + return CallingConventionNaked; + if (fn_proto->is_stdcallcc) + return CallingConventionStdcall; + if (fn_proto->is_async) + return CallingConventionAsync; + // Compatible with the C ABI + if (fn_proto->is_extern || fn_proto->is_export) + return CallingConventionC; + + return CallingConventionUnspecified; +} + +void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, CallingConvention cc, size_t param_count_alloc) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - if (fn_proto->cc == CallingConventionUnspecified) { - bool extern_abi = fn_proto->is_extern || fn_proto->is_export; - fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; - } else { - fn_type_id->cc = fn_proto->cc; - } - + fn_type_id->cc = cc; fn_type_id->param_count = fn_proto->params.length; fn_type_id->param_info = allocate(param_count_alloc); fn_type_id->next_param_index = 0; @@ -1690,7 +1707,8 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { return type_allowed_in_extern(g, type_entry->data.array.child_type, result); case ZigTypeIdFn: *result = type_entry->data.fn.fn_type_id.cc == CallingConventionC || - type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall; + type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall || + type_entry->data.fn.fn_type_id.cc == CallingConventionAAPCS; return ErrorNone; case ZigTypeIdPointer: if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) @@ -1750,7 +1768,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc Error err; FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); + init_fn_type_id(&fn_type_id, proto_node, fn_entry->cc, proto_node->data.fn_proto.params.length); for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); @@ -3393,27 +3411,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, false); } - if (fn_proto->is_export) { - switch (fn_proto->cc) { - case CallingConventionAsync: { - add_node_error(g, fn_def_node, - buf_sprintf("exported function cannot be async")); - } break; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionCold: - case CallingConventionStdcall: - case CallingConventionUnspecified: - // An exported function without a specific calling - // convention defaults to C - CallingConvention cc = (fn_proto->cc != CallingConventionUnspecified) ? - fn_proto->cc : CallingConventionC; - add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), - GlobalLinkageIdStrong, cc); - break; - } - } - if (!is_extern) { fn_table_entry->fndef_scope = create_fndef_scope(g, fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry); @@ -3432,6 +3429,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; + fn_table_entry->cc = cc_from_fn_proto(fn_proto); + if (fn_proto->callconv_expr != nullptr) { + ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); + + ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr, + cc_enum_value, nullptr, UndefBad); + if (type_is_invalid(result_val->type)) { + fn_table_entry->type_entry = g->builtin_types.entry_invalid; + tld_fn->base.resolution = TldResolutionInvalid; + return; + } + + fn_table_entry->cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); + } + fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); if (fn_proto->section_expr != nullptr) { @@ -3450,10 +3462,42 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { g->fn_defs.append(fn_table_entry); } + const CallingConvention fn_cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; + + if (fn_proto->is_export) { + switch (fn_cc) { + case CallingConventionAsync: + add_node_error(g, fn_def_node, + buf_sprintf("exported function cannot be async")); + tld_fn->base.resolution = TldResolutionInvalid; + return; + case CallingConventionC: + case CallingConventionCold: + case CallingConventionNaked: + case CallingConventionInterrupt: + case CallingConventionSignal: + case CallingConventionStdcall: + case CallingConventionFastcall: + case CallingConventionVectorcall: + case CallingConventionAPCS: + case CallingConventionAAPCS: + case CallingConventionAAPCSVFP: + add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), + GlobalLinkageIdStrong, fn_cc); + break; + case CallingConventionUnspecified: + // An exported function without a specific calling + // convention defaults to C + add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), + GlobalLinkageIdStrong, CallingConventionC); + break; + } + } + // if the calling convention implies that it cannot be async, we save that for later // and leave the value to be nullptr to indicate that we have not emitted possible // compile errors for improperly calling async functions. - if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { + if (fn_cc == CallingConventionAsync) { fn_table_entry->inferred_async_node = fn_table_entry->proto_node; } } else if (source_node->type == NodeTypeTestDecl) { -- cgit v1.2.3 From 271fc6a2479a1c5f2f914c1c40a848bf1b9d70d8 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 24 Dec 2019 11:28:10 +0100 Subject: Catch more errors during the type resolution phase Returning the uninitialized/stale error condition made the compiler turn a blind eye to some problems. --- src/analyze.cpp | 9 +++++---- src/codegen.cpp | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'src/analyze.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 7e672e1936..9a4b1449b6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2180,7 +2180,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { ZigType *field_type = resolve_struct_field_type(g, field); if (field_type == nullptr) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; + return ErrorSemanticAnalyzeFail; } if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; @@ -2270,7 +2270,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { ZigType *field_type = resolve_struct_field_type(g, field); if (field_type == nullptr) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; + return ErrorSemanticAnalyzeFail; } if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { @@ -2340,7 +2340,7 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { &field->align)) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; + return ErrorSemanticAnalyzeFail; } add_node_error(g, field->decl_node, buf_create_from_str("TODO implement field alignment syntax for unions. https://github.com/ziglang/zig/issues/3125")); @@ -2467,6 +2467,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } + if (is_packed) { if ((err = emit_error_unless_type_allowed_in_packed_union(g, field_type, union_field->decl_node))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -2925,7 +2926,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { &field->align)) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; + return ErrorSemanticAnalyzeFail; } } else if (packed) { field->align = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index c5611f3e2c..b83767f9d6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -290,10 +290,16 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) { case CallingConventionFastcall: if (g->zig_target->arch == ZigLLVM_x86) return LLVMX86FastcallCallConv; - return LLVMFastCallConv; + return LLVMCCallConv; case CallingConventionVectorcall: if (g->zig_target->arch == ZigLLVM_x86) return LLVMX86VectorCallCallConv; + // XXX Enable this when the C API exports this enum member too +#if 0 + if (target_is_arm(g->zig_target) && + target_arch_pointer_bit_width(g->zig_target->arch) == 64) + return LLVMAARCH64VectorCallCallConv; +#endif return LLVMCCallConv; case CallingConventionAsync: return LLVMFastCallConv; @@ -310,7 +316,8 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) { return LLVMARMAAPCSVFPCallConv; return LLVMCCallConv; case CallingConventionInterrupt: - if (g->zig_target->arch == ZigLLVM_x86 || g->zig_target->arch == ZigLLVM_x86_64) + if (g->zig_target->arch == ZigLLVM_x86 || + g->zig_target->arch == ZigLLVM_x86_64) return LLVMX86INTRCallConv; if (g->zig_target->arch == ZigLLVM_avr) return LLVMAVRINTRCallConv; -- cgit v1.2.3 From 0ccac79c8ebc1ed56dbdab068076a86924a015bc Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 29 Dec 2019 19:34:54 +0100 Subject: Implement Thiscall CC --- lib/std/builtin.zig | 1 + src-self-hosted/translate_c.zig | 1 + src/all_types.hpp | 1 + src/analyze.cpp | 26 +++++++++++++++----------- src/codegen.cpp | 12 +++++++++--- src/ir.cpp | 1 + test/translate_c.zig | 2 ++ 7 files changed, 30 insertions(+), 14 deletions(-) (limited to 'src/analyze.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 87b95786ec..9b3be8f424 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -104,6 +104,7 @@ pub const CallingConvention = enum { Stdcall, Fastcall, Vectorcall, + Thiscall, APCS, AAPCS, AAPCSVFP, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 194217a600..1323c1a86d 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -3975,6 +3975,7 @@ fn transCC( .X86StdCall => return CallingConvention.Stdcall, .X86FastCall => return CallingConvention.Fastcall, .X86VectorCall, .AArch64VectorCall => return CallingConvention.Vectorcall, + .X86ThisCall => return CallingConvention.Thiscall, .AAPCS => return CallingConvention.AAPCS, .AAPCS_VFP => return CallingConvention.AAPCSVFP, else => return revertAndWarn( diff --git a/src/all_types.hpp b/src/all_types.hpp index b2c3712f50..9ce29b6873 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -68,6 +68,7 @@ enum CallingConvention { CallingConventionStdcall, CallingConventionFastcall, CallingConventionVectorcall, + CallingConventionThiscall, CallingConventionAPCS, CallingConventionAAPCS, CallingConventionAAPCSVFP, diff --git a/src/analyze.cpp b/src/analyze.cpp index 9a4b1449b6..b71d3322a1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -929,6 +929,7 @@ const char *calling_convention_name(CallingConvention cc) { case CallingConventionStdcall: return "Stdcall"; case CallingConventionFastcall: return "Fastcall"; case CallingConventionVectorcall: return "Vectorcall"; + case CallingConventionThiscall: return "Thiscall"; case CallingConventionAPCS: return "Apcs"; case CallingConventionAAPCS: return "Aapcs"; case CallingConventionAAPCSVFP: return "Aapcsvfp"; @@ -949,6 +950,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { case CallingConventionStdcall: case CallingConventionFastcall: case CallingConventionVectorcall: + case CallingConventionThiscall: case CallingConventionAPCS: case CallingConventionAAPCS: case CallingConventionAAPCSVFP: @@ -1706,9 +1708,7 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { case ZigTypeIdArray: return type_allowed_in_extern(g, type_entry->data.array.child_type, result); case ZigTypeIdFn: - *result = type_entry->data.fn.fn_type_id.cc == CallingConventionC || - type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall || - type_entry->data.fn.fn_type_id.cc == CallingConventionAAPCS; + *result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc); return ErrorNone; case ZigTypeIdPointer: if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) @@ -3445,24 +3445,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); } - fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); - if (fn_proto->section_expr != nullptr) { if (!analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name)) { fn_table_entry->type_entry = g->builtin_types.entry_invalid; + tld_fn->base.resolution = TldResolutionInvalid; + return; } } - if (fn_table_entry->type_entry->id == ZigTypeIdInvalid) { + fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); + + if (type_is_invalid(fn_table_entry->type_entry)) { tld_fn->base.resolution = TldResolutionInvalid; return; } - if (!fn_table_entry->type_entry->data.fn.is_generic) { - if (fn_def_node) - g->fn_defs.append(fn_table_entry); - } - const CallingConvention fn_cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; if (fn_proto->is_export) { @@ -3470,6 +3467,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { case CallingConventionAsync: add_node_error(g, fn_def_node, buf_sprintf("exported function cannot be async")); + fn_table_entry->type_entry = g->builtin_types.entry_invalid; tld_fn->base.resolution = TldResolutionInvalid; return; case CallingConventionC: @@ -3480,6 +3478,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { case CallingConventionStdcall: case CallingConventionFastcall: case CallingConventionVectorcall: + case CallingConventionThiscall: case CallingConventionAPCS: case CallingConventionAAPCS: case CallingConventionAAPCSVFP: @@ -3495,6 +3494,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } + if (!fn_table_entry->type_entry->data.fn.is_generic) { + if (fn_def_node) + g->fn_defs.append(fn_table_entry); + } + // if the calling convention implies that it cannot be async, we save that for later // and leave the value to be nullptr to indicate that we have not emitted possible // compile errors for improperly calling async functions. diff --git a/src/codegen.cpp b/src/codegen.cpp index b83767f9d6..23a9103877 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -301,6 +301,10 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) { return LLVMAARCH64VectorCallCallConv; #endif return LLVMCCallConv; + case CallingConventionThiscall: + if (g->zig_target->arch == ZigLLVM_x86) + return LLVMX86ThisCallCallConv; + return LLVMCCallConv; case CallingConventionAsync: return LLVMFastCallConv; case CallingConventionAPCS: @@ -424,6 +428,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { case CallingConventionStdcall: case CallingConventionFastcall: case CallingConventionVectorcall: + case CallingConventionThiscall: case CallingConventionAPCS: case CallingConventionAAPCS: case CallingConventionAAPCSVFP: @@ -8512,9 +8517,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { static_assert(CallingConventionStdcall == 7, ""); static_assert(CallingConventionFastcall == 8, ""); static_assert(CallingConventionVectorcall == 9, ""); - static_assert(CallingConventionAPCS == 10, ""); - static_assert(CallingConventionAAPCS == 11, ""); - static_assert(CallingConventionAAPCSVFP == 12, ""); + static_assert(CallingConventionThiscall == 10, ""); + static_assert(CallingConventionAPCS == 11, ""); + static_assert(CallingConventionAAPCS == 12, ""); + static_assert(CallingConventionAAPCSVFP == 13, ""); static_assert(FnInlineAuto == 0, ""); static_assert(FnInlineAlways == 1, ""); diff --git a/src/ir.cpp b/src/ir.cpp index da402887c4..de84852f59 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16752,6 +16752,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case CallingConventionStdcall: case CallingConventionFastcall: case CallingConventionVectorcall: + case CallingConventionThiscall: case CallingConventionAPCS: case CallingConventionAAPCS: case CallingConventionAAPCSVFP: diff --git a/test/translate_c.zig b/test/translate_c.zig index 78793b01cd..ceeff0c91e 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -850,11 +850,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\void __attribute__((stdcall)) foo2(float *a); \\void __attribute__((vectorcall)) foo3(float *a); \\void __attribute__((cdecl)) foo4(float *a); + \\void __attribute__((thiscall)) foo5(float *a); , &[_][]const u8{ \\pub fn foo1(a: [*c]f32) callconv(.Fastcall) void; \\pub fn foo2(a: [*c]f32) callconv(.Stdcall) void; \\pub fn foo3(a: [*c]f32) callconv(.Vectorcall) void; \\pub extern fn foo4(a: [*c]f32) void; + \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void; }); cases.addWithTarget("Calling convention", tests.Target{ -- cgit v1.2.3 From 5951b79af40212754071157596b8aebbe2414ffb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 6 Jan 2020 15:23:05 -0500 Subject: remove stdcallcc, extern, nakedcc from stage1; zig fmt rewrites --- lib/std/builtin.zig | 1 - lib/std/zig/parser_test.zig | 4 +++- lib/std/zig/render.zig | 15 ++++++++++----- src/all_types.hpp | 3 --- src/analyze.cpp | 22 ++++++++++------------ src/codegen.cpp | 2 +- src/ir.cpp | 18 ++++++------------ src/parser.cpp | 12 +----------- src/tokenizer.cpp | 4 ---- src/tokenizer.hpp | 2 -- 10 files changed, 31 insertions(+), 52 deletions(-) (limited to 'src/analyze.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 9b3be8f424..288e8f8897 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -322,7 +322,6 @@ pub const TypeInfo = union(enum) { pub const FnDecl = struct { fn_type: type, inline_type: Inline, - calling_convention: CallingConvention, is_var_args: bool, is_extern: bool, is_export: bool, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 018ba9653f..97df2dff15 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -10,13 +10,15 @@ test "zig fmt: change @typeOf to @TypeOf" { } // TODO: Remove nakedcc/stdcallcc once zig 0.6.0 is released. See https://github.com/ziglang/zig/pull/3977 -test "zig fmt: convert nakedcc/stdcallcc into callconv(...)" { +test "zig fmt: convert extern/nakedcc/stdcallcc into callconv(...)" { try testTransform( \\nakedcc fn foo1() void {} \\stdcallcc fn foo2() void {} + \\extern fn foo3() void {} , \\fn foo1() callconv(.Naked) void {} \\fn foo2() callconv(.Stdcall) void {} + \\fn foo3() callconv(.C) void {} \\ ); } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 626017dd66..2b1a739186 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1311,17 +1311,22 @@ fn renderExpression( try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub } + // Some extra machinery is needed to rewrite the old-style cc + // notation to the new callconv one + var cc_rewrite_str: ?[*:0]const u8 = null; if (fn_proto.extern_export_inline_token) |extern_export_inline_token| { - try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export + const tok = tree.tokens.at(extern_export_inline_token); + if (tok.id != .Keyword_extern or fn_proto.body_node == null) { + try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export + } else { + cc_rewrite_str = ".C"; + } } if (fn_proto.lib_name) |lib_name| { try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); } - // Some extra machinery is needed to rewrite the old-style cc - // notation to the new callconv one - var cc_rewrite_str: ?[*:0]const u8 = null; if (fn_proto.cc_token) |cc_token| { var str = tree.tokenSlicePtr(tree.tokens.at(cc_token)); if (mem.eql(u8, str, "stdcallcc")) { @@ -1405,7 +1410,7 @@ fn renderExpression( const callconv_lparen = tree.prevToken(callconv_expr.firstToken()); const callconv_kw = tree.prevToken(callconv_lparen); - try renderToken(tree, stream, callconv_kw, indent, start_col, Space.None); // section + try renderToken(tree, stream, callconv_kw, indent, start_col, Space.None); // callconv try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // ( try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None); try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // ) diff --git a/src/all_types.hpp b/src/all_types.hpp index 3e8516529a..fe77d3db3b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -653,8 +653,6 @@ struct AstNodeFnProto { Buf doc_comments; FnInline fn_inline; - bool is_nakedcc; - bool is_stdcallcc; bool is_async; VisibMod visib_mod; @@ -1610,7 +1608,6 @@ struct ZigFn { Buf **param_names; IrInstruction *err_code_spill; AstNode *assumed_non_async; - CallingConvention cc; AstNode *fn_no_inline_set_node; AstNode *fn_static_eval_set_node; diff --git a/src/analyze.cpp b/src/analyze.cpp index 5fb99ef1f3..a7763fea61 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1451,8 +1451,6 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); buf_resize(&fn_type->name, 0); - if (fn_type->data.fn.fn_type_id.cc == CallingConventionC) - buf_append_str(&fn_type->name, "extern "); buf_appendf(&fn_type->name, "fn("); size_t i = 0; for (; i < fn_type_id->next_param_index; i += 1) { @@ -1465,7 +1463,7 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { buf_appendf(&fn_type->name, "%svar", comma_str); } buf_append_str(&fn_type->name, ")"); - if (fn_type_id->cc != CallingConventionUnspecified && fn_type_id->cc != CallingConventionC) { + if (fn_type_id->cc != CallingConventionUnspecified) { buf_appendf(&fn_type->name, " callconv(%s)", calling_convention_name(fn_type_id->cc)); } buf_append_str(&fn_type->name, " var"); @@ -1479,10 +1477,6 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { } CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { - if (fn_proto->is_nakedcc) - return CallingConventionNaked; - if (fn_proto->is_stdcallcc) - return CallingConventionStdcall; if (fn_proto->is_async) return CallingConventionAsync; // Compatible with the C ABI @@ -1764,13 +1758,15 @@ ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { return err_set_type; } -static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, ZigFn *fn_entry) { +static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, ZigFn *fn_entry, + CallingConvention cc) +{ assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; Error err; FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, fn_entry->cc, proto_node->data.fn_proto.params.length); + init_fn_type_id(&fn_type_id, proto_node, cc, proto_node->data.fn_proto.params.length); for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); @@ -3432,7 +3428,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; - fn_table_entry->cc = cc_from_fn_proto(fn_proto); + CallingConvention cc; if (fn_proto->callconv_expr != nullptr) { ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); @@ -3444,7 +3440,9 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { return; } - fn_table_entry->cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); + cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); + } else { + cc = cc_from_fn_proto(fn_proto); } if (fn_proto->section_expr != nullptr) { @@ -3455,7 +3453,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } - fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); + fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry, cc); if (type_is_invalid(fn_table_entry->type_entry)) { tld_fn->base.resolution = TldResolutionInvalid; diff --git a/src/codegen.cpp b/src/codegen.cpp index cbb5e35a57..59f69539bc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -519,7 +519,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { if (cc == CallingConventionNaked) { addLLVMFnAttr(llvm_fn, "naked"); } else { - ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc)); + ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc)); } bool want_cold = fn->is_cold || cc == CallingConventionCold; diff --git a/src/ir.cpp b/src/ir.cpp index 78be3256c0..4a91046b7c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18263,7 +18263,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstruction *source_i buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); impl_fn->fndef_scope = create_fndef_scope(ira->codegen, impl_fn->body_node, parent_scope, impl_fn); impl_fn->child_scope = &impl_fn->fndef_scope->base; - impl_fn->cc = fn_entry->cc; FnTypeId inst_fn_type_id = {0}; init_fn_type_id(&inst_fn_type_id, fn_proto_node, fn_type_id->cc, new_fn_arg_count); inst_fn_type_id.param_count = 0; @@ -22599,29 +22598,24 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr fn_decl_fields[1]->special = ConstValSpecialStatic; fn_decl_fields[1]->type = type_info_fn_decl_inline_type; bigint_init_unsigned(&fn_decl_fields[1]->data.x_enum_tag, fn_entry->fn_inline); - // calling_convention: TypeInfo.CallingConvention - ensure_field_index(fn_decl_val->type, "calling_convention", 2); - fn_decl_fields[2]->special = ConstValSpecialStatic; - fn_decl_fields[2]->type = get_builtin_type(ira->codegen, "CallingConvention"); - bigint_init_unsigned(&fn_decl_fields[2]->data.x_enum_tag, fn_entry->cc); // is_var_args: bool - ensure_field_index(fn_decl_val->type, "is_var_args", 3); + ensure_field_index(fn_decl_val->type, "is_var_args", 2); bool is_varargs = fn_node->is_var_args; fn_decl_fields[3]->special = ConstValSpecialStatic; fn_decl_fields[3]->type = ira->codegen->builtin_types.entry_bool; fn_decl_fields[3]->data.x_bool = is_varargs; // is_extern: bool - ensure_field_index(fn_decl_val->type, "is_extern", 4); + ensure_field_index(fn_decl_val->type, "is_extern", 3); fn_decl_fields[4]->special = ConstValSpecialStatic; fn_decl_fields[4]->type = ira->codegen->builtin_types.entry_bool; fn_decl_fields[4]->data.x_bool = fn_node->is_extern; // is_export: bool - ensure_field_index(fn_decl_val->type, "is_export", 5); + ensure_field_index(fn_decl_val->type, "is_export", 4); fn_decl_fields[5]->special = ConstValSpecialStatic; fn_decl_fields[5]->type = ira->codegen->builtin_types.entry_bool; fn_decl_fields[5]->data.x_bool = fn_node->is_export; // lib_name: ?[]const u8 - ensure_field_index(fn_decl_val->type, "lib_name", 6); + ensure_field_index(fn_decl_val->type, "lib_name", 5); fn_decl_fields[6]->special = ConstValSpecialStatic; ZigType *u8_ptr = get_pointer_to_type_extra( ira->codegen, ira->codegen->builtin_types.entry_u8, @@ -22637,12 +22631,12 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr fn_decl_fields[6]->data.x_optional = nullptr; } // return_type: type - ensure_field_index(fn_decl_val->type, "return_type", 7); + ensure_field_index(fn_decl_val->type, "return_type", 6); fn_decl_fields[7]->special = ConstValSpecialStatic; fn_decl_fields[7]->type = ira->codegen->builtin_types.entry_type; fn_decl_fields[7]->data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; // arg_names: [][] const u8 - ensure_field_index(fn_decl_val->type, "arg_names", 8); + ensure_field_index(fn_decl_val->type, "arg_names", 7); size_t fn_arg_count = fn_entry->variable_list.length; ZigValue *fn_arg_name_array = create_const_vals(1); fn_arg_name_array->special = ConstValSpecialStatic; diff --git a/src/parser.cpp b/src/parser.cpp index 65ea9ac203..f6f5811e63 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2117,20 +2117,10 @@ static AstNode *ast_parse_callconv(ParseContext *pc) { } // FnCC -// <- KEYWORD_nakedcc -// / KEYWORD_stdcallcc -// / KEYWORD_extern +// <- KEYWORD_extern // / KEYWORD_async static Optional ast_parse_fn_cc(ParseContext *pc) { AstNodeFnProto res = {}; - if (eat_token_if(pc, TokenIdKeywordNakedCC) != nullptr) { - res.is_nakedcc = true; - return Optional::some(res); - } - if (eat_token_if(pc, TokenIdKeywordStdcallCC) != nullptr) { - res.is_stdcallcc = true; - return Optional::some(res); - } if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) { res.is_async = true; return Optional::some(res); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index fb58bc19bb..9182c5227a 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -127,7 +127,6 @@ static const struct ZigKeyword zig_keywords[] = { {"for", TokenIdKeywordFor}, {"if", TokenIdKeywordIf}, {"inline", TokenIdKeywordInline}, - {"nakedcc", TokenIdKeywordNakedCC}, {"noalias", TokenIdKeywordNoAlias}, {"noasync", TokenIdKeywordNoAsync}, {"noinline", TokenIdKeywordNoInline}, @@ -139,7 +138,6 @@ static const struct ZigKeyword zig_keywords[] = { {"resume", TokenIdKeywordResume}, {"return", TokenIdKeywordReturn}, {"linksection", TokenIdKeywordLinkSection}, - {"stdcallcc", TokenIdKeywordStdcallCC}, {"struct", TokenIdKeywordStruct}, {"suspend", TokenIdKeywordSuspend}, {"switch", TokenIdKeywordSwitch}, @@ -1562,7 +1560,6 @@ const char * token_name(TokenId id) { case TokenIdKeywordFor: return "for"; case TokenIdKeywordIf: return "if"; case TokenIdKeywordInline: return "inline"; - case TokenIdKeywordNakedCC: return "nakedcc"; case TokenIdKeywordNoAlias: return "noalias"; case TokenIdKeywordNoAsync: return "noasync"; case TokenIdKeywordNoInline: return "noinline"; @@ -1573,7 +1570,6 @@ const char * token_name(TokenId id) { case TokenIdKeywordPub: return "pub"; case TokenIdKeywordReturn: return "return"; case TokenIdKeywordLinkSection: return "linksection"; - case TokenIdKeywordStdcallCC: return "stdcallcc"; case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordSwitch: return "switch"; case TokenIdKeywordTest: return "test"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index eacdaad98d..a893cc2373 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -77,7 +77,6 @@ enum TokenId { TokenIdKeywordInline, TokenIdKeywordNoInline, TokenIdKeywordLinkSection, - TokenIdKeywordNakedCC, TokenIdKeywordNoAlias, TokenIdKeywordNoAsync, TokenIdKeywordNull, @@ -87,7 +86,6 @@ enum TokenId { TokenIdKeywordPub, TokenIdKeywordResume, TokenIdKeywordReturn, - TokenIdKeywordStdcallCC, TokenIdKeywordStruct, TokenIdKeywordSuspend, TokenIdKeywordSwitch, -- cgit v1.2.3 From be2483c576850c038d84cade26c1a509a940f047 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 6 Jan 2020 18:20:31 -0500 Subject: fix test suite regressions --- doc/langref.html.in | 2 +- src/analyze.cpp | 10 ++++------ test/compile_errors.zig | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'src/analyze.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 476e370358..f934f923f0 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7735,7 +7735,7 @@ const Derp = @OpaqueType(); const Wat = @OpaqueType(); extern fn bar(d: *Derp) void; -export fn foo(w: *Wat) void { +fn foo(w: *Wat) callconv(.C) void { bar(w); } diff --git a/src/analyze.cpp b/src/analyze.cpp index a7763fea61..b15d986558 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1010,8 +1010,6 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { // populate the name of the type buf_resize(&fn_type->name, 0); - if (fn_type->data.fn.fn_type_id.cc == CallingConventionC) - buf_append_str(&fn_type->name, "extern "); buf_appendf(&fn_type->name, "fn("); for (size_t i = 0; i < fn_type_id->param_count; i += 1) { FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; @@ -1030,8 +1028,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (fn_type_id->alignment != 0) { buf_appendf(&fn_type->name, " align(%" PRIu32 ")", fn_type_id->alignment); } - if (fn_type_id->cc != CallingConventionUnspecified && fn_type_id->cc != CallingConventionC) { - buf_appendf(&fn_type->name, " callconv(%s)", calling_convention_name(fn_type_id->cc)); + if (fn_type_id->cc != CallingConventionUnspecified) { + buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); } buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name)); @@ -1464,7 +1462,7 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { } buf_append_str(&fn_type->name, ")"); if (fn_type_id->cc != CallingConventionUnspecified) { - buf_appendf(&fn_type->name, " callconv(%s)", calling_convention_name(fn_type_id->cc)); + buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); } buf_append_str(&fn_type->name, " var"); @@ -4385,7 +4383,7 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { } else if (ptr_type->id == ZigTypeIdFn) { // I tried making this use LLVMABIAlignmentOfType but it trips this assertion in LLVM: // "Cannot getTypeInfo() on a type that is unsized!" - // when getting the alignment of `?extern fn() void`. + // when getting the alignment of `?fn() callconv(.C) void`. // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; } else if (ptr_type->id == ZigTypeIdAnyFrame) { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index bf3ee14bec..fb1cf88e74 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2843,7 +2843,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() void { \\ foo(); \\} - \\nakedcc fn foo() void { } + \\fn foo() callconv(.Naked) void { } , &[_][]const u8{ "tmp.zig:2:5: error: unable to call function with naked calling convention", "tmp.zig:4:1: note: declared here", @@ -2978,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , &[_][]const u8{ "tmp.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'", - "tmp.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'", + "tmp.zig:7:11: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'", }); cases.add("implicit semicolon - block statement", @@ -5663,7 +5663,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); cases.add("@setAlignStack in naked function", - \\export nakedcc fn entry() void { + \\export fn entry() callconv(.Naked) void { \\ @setAlignStack(16); \\} , &[_][]const u8{ -- cgit v1.2.3