Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

transFnDecl

Translator.transFnDecl
fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!void

File

lib/compiler/translate-c/Translator.zig:764

Code

fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!void {
    const func_ty = function.qt.get(t.comp, .func).?;

    const fn_name = t.tree.tokSlice(function.name_tok);
    if (scope.getAlias(fn_name) != null or t.global_scope.containsNow(fn_name))
        return; // Avoid processing this decl twice

    const fn_decl_loc = function.name_tok;
    const has_body = function.body != null and func_ty.kind != .variadic and t.func_bodies;
    if (function.body != null and func_ty.kind == .variadic) {
        try t.warn(scope, function.name_tok, "TODO unable to translate variadic function, demoted to extern", .{});
    }

    const is_always_inline = has_body and function.qt.getAttribute(t.comp, .always_inline) != null;
    const proto_ctx: FnProtoContext = .{
        .fn_name = fn_name,
        .is_always_inline = is_always_inline,
        .is_extern = !has_body,
        .is_export = !function.static and has_body and !is_always_inline and !function.@"inline",
        .is_pub = scope.id == .root and (!function.static or t.pub_static),
        .has_body = has_body,
        .cc = if (function.qt.getAttribute(t.comp, .calling_convention)) |some| switch (some.cc) {
            .c => .c,
            .stdcall => .x86_stdcall,
            .thiscall => .x86_thiscall,
            .fastcall => .x86_fastcall,
            .regcall => .x86_regcall,
            .riscv_vector => .riscv_vector,
            .aarch64_sve_pcs => .aarch64_sve_pcs,
            .aarch64_vector_pcs => .aarch64_vfabi,
            .arm_aapcs => .arm_aapcs,
            .arm_aapcs_vfp => .arm_aapcs_vfp,
            .vectorcall => switch (t.comp.target.cpu.arch) {
                .x86 => .x86_vectorcall,
                .aarch64, .aarch64_be => .aarch64_vfabi,
                else => .c,
            },
            .x86_64_sysv => .x86_64_sysv,
            .x86_64_win => .x86_64_win,
        } else .c,
    };

    const proto_node = t.transFnType(&t.global_scope.base, function.qt, func_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) {
        error.UnsupportedType => {
            return t.failDecl(scope, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
        },
        error.OutOfMemory => |e| return e,
    };

    const proto_payload = proto_node.castTag(.func).?;
    if (!has_body) {
        if (scope.id != .root) {
            const bs: *Scope.Block = try scope.findBlockScope(t);
            const mangled_name = try bs.createMangledName(fn_name, false, Scope.Block.extern_local_prefix);
            const wrapped = try ZigTag.wrapped_local.create(t.arena, .{ .name = mangled_name, .init = proto_node });
            try scope.appendNode(wrapped);
            try bs.discardVariable(mangled_name);
            return;
        }
        try t.global_scope.addMemberFunction(func_ty, proto_payload);
        return t.addTopLevelDecl(fn_name, proto_node);
    }

    // actual function definition with body
    const body_stmt = function.body.?.get(t.tree).compound_stmt;
    var block_scope = try Scope.Block.init(t, &t.global_scope.base, false);
    block_scope.return_type = func_ty.return_type;
    defer block_scope.deinit();

    var param_id: c_uint = 0;
    for (proto_payload.data.params, func_ty.params) |*param, param_info| {
        const param_name = param.name orelse {
            proto_payload.data.is_extern = true;
            proto_payload.data.is_export = false;
            proto_payload.data.is_inline = false;
            try t.warn(&t.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
            return t.addTopLevelDecl(fn_name, proto_node);
        };

        const is_const = param_info.qt.@"const";

        const mangled_param_name = try block_scope.makeMangledName(param_name);
        param.name = mangled_param_name;

        if (!is_const) {
            const bare_arg_name = try std.fmt.allocPrint(t.arena, "arg_{s}", .{mangled_param_name});
            const arg_name = try block_scope.makeMangledName(bare_arg_name);
            param.name = arg_name;

            const redecl_node = try ZigTag.arg_redecl.create(t.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
            try block_scope.statements.append(t.gpa, redecl_node);
        }
        try block_scope.discardVariable(mangled_param_name);

        param_id += 1;
    }

    t.transCompoundStmtInline(body_stmt, &block_scope) catch |err| switch (err) {
        error.OutOfMemory => |e| return e,
        error.SelfReferential => unreachable,
        error.UnsupportedTranslation,
        error.UnsupportedType,
        => {
            proto_payload.data.is_extern = true;
            proto_payload.data.is_export = false;
            proto_payload.data.is_inline = false;
            try t.warn(&t.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
            return t.addTopLevelDecl(fn_name, proto_node);
        },
    };

    try t.global_scope.addMemberFunction(func_ty, proto_payload);
    proto_payload.data.body = try block_scope.complete();
    return t.addTopLevelDecl(fn_name, proto_node);
}