diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-06 14:07:56 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-01-06 14:07:56 -0500 |
| commit | 0a9daeb37e997ff75dcd16d1fc3b4cc143314e85 (patch) | |
| tree | 05ca7f6b64b1e40fc16a595816f3a632a986617c /src/analyze.cpp | |
| parent | c30106c90665079f525129e344cc1c13e4db162b (diff) | |
| parent | d09bd3d86c4d36ad608a91b36c9a6eb6208c9626 (diff) | |
| download | zig-0a9daeb37e997ff75dcd16d1fc3b4cc143314e85.tar.gz zig-0a9daeb37e997ff75dcd16d1fc3b4cc143314e85.zip | |
Merge branch 'cc-work' of https://github.com/LemonBoy/zig into LemonBoy-cc-work
Diffstat (limited to 'src/analyze.cpp')
| -rw-r--r-- | src/analyze.cpp | 173 |
1 files changed, 111 insertions, 62 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index aeef6cf35b..5fb99ef1f3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -919,24 +919,20 @@ 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 CallingConventionThiscall: return "Thiscall"; + case CallingConventionAPCS: return "Apcs"; + case CallingConventionAAPCS: return "Aapcs"; + case CallingConventionAAPCSVFP: return "Aapcsvfp"; } zig_unreachable(); } @@ -949,7 +945,15 @@ 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 CallingConventionThiscall: + case CallingConventionAPCS: + case CallingConventionAAPCS: + case CallingConventionAAPCSVFP: return false; } zig_unreachable(); @@ -1006,8 +1010,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 +1030,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. @@ -1444,8 +1451,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) { @@ -1457,7 +1464,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; @@ -1467,17 +1478,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<FnTypeParamInfo>(param_count_alloc); fn_type_id->next_param_index = 0; @@ -1691,8 +1710,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; + *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))) @@ -1752,7 +1770,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); @@ -2164,7 +2182,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; @@ -2254,7 +2272,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))) { @@ -2324,7 +2342,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")); @@ -2451,6 +2469,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; @@ -2909,7 +2928,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; @@ -3395,27 +3414,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); @@ -3434,19 +3432,70 @@ 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->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); + 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); + } 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; } + 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")); + fn_table_entry->type_entry = g->builtin_types.entry_invalid; + tld_fn->base.resolution = TldResolutionInvalid; + return; + case CallingConventionC: + case CallingConventionCold: + case CallingConventionNaked: + case CallingConventionInterrupt: + case CallingConventionSignal: + case CallingConventionStdcall: + case CallingConventionFastcall: + case CallingConventionVectorcall: + case CallingConventionThiscall: + 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 (!fn_table_entry->type_entry->data.fn.is_generic) { if (fn_def_node) g->fn_defs.append(fn_table_entry); @@ -3455,7 +3504,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { // 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) { |
