Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
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 standard library. Private Function

structDeclInner

Private Function
std.zig.AstGen.structDeclInner
fn structDeclInner(
    gz: *GenZir,
    scope: *Scope,
    node: Ast.Node.Index,
    container_decl: Ast.full.ContainerDecl,
    layout: std.lang.Type.ContainerLayout,
    maybe_backing_int_node: Ast.Node.OptionalIndex,
    name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref

Params

Errors

OutOfMemory
AnalysisFail

File

zig/AstGen.zig:4822
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
fn structDeclInner(
    gz: *GenZir,
    scope: *Scope,
    node: Ast.Node.Index,
    container_decl: Ast.full.ContainerDecl,
    layout: std.lang.Type.ContainerLayout,
    maybe_backing_int_node: Ast.Node.OptionalIndex,
    name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref {
    const astgen = gz.astgen;
    const gpa = astgen.gpa;
    const tree = astgen.tree;

    is_tuple: {
        const tuple_field_node = for (container_decl.ast.members) |member_node| {
            const container_field = tree.fullContainerField(member_node) orelse continue;
            if (container_field.ast.tuple_like) break member_node;
        } else break :is_tuple;

        if (node == .root) {
            return astgen.failNode(tuple_field_node, "file cannot be a tuple", .{});
        } else {
            return tupleDecl(gz, scope, node, container_decl, layout, maybe_backing_int_node);
        }
    }

    astgen.advanceSourceCursorToNode(node);

    const decl_inst = try gz.reserveInstructionIndex();
    const src_line = astgen.source_line;
    const src_column = astgen.source_column;

    if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {
        try gz.setStruct(decl_inst, .{
            .src_line = src_line,
            .src_column = src_column,
            .src_node = node,
            .name_strat = name_strat,
            .layout = layout,
            .backing_int_type_body_len = null,
            .decls_len = 0,
            .fields_len = 0,
            .any_field_aligns = false,
            .any_field_defaults = false,
            .any_comptime_fields = false,
            .fields_hash = @splat(0),
            .captures = &.{},
            .capture_names = &.{},
            .remaining = &.{},
        });
        return decl_inst.toRef();
    }

    var namespace: Scope.Namespace = .{
        .parent = scope,
        .node = node,
        .inst = decl_inst,
        .declaring_gz = gz,
        .maybe_generic = astgen.within_fn,
    };
    defer namespace.deinit(gpa);

    // The struct_decl instruction introduces a scope in which the decls of the struct
    // are in scope, so that field types, alignments, and default value expressions
    // can refer to decls within the struct itself.
    var block_scope: GenZir = .{
        .parent = &namespace.base,
        .decl_node_index = node,
        .decl_line = gz.decl_line,
        .astgen = astgen,
        .is_comptime = true,
        .instructions = gz.instructions,
        .instructions_top = gz.instructions.items.len,
    };
    defer block_scope.unstack();

    const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct");

    var scratch: Scratch = .init(astgen);
    defer scratch.reset();

    // Replicate the structure of the ZIR trailing data in `scratch`
    var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
    const field_names = try scratch.addSlice(scan_result.fields_len);
    const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
    const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
    const field_default_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
    const field_comptime_bits = try scratch.addOptionalSlice(
        scan_result.any_comptime_fields,
        @divCeil(scan_result.fields_len, 32),
    );
    if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0);

    const old_hasher = astgen.src_hasher;
    defer astgen.src_hasher = old_hasher;
    astgen.src_hasher = .init(.{});

    // Before any field bodies comes the backing int type, if specified.
    const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: {
        if (layout != .@"packed") return astgen.failNode(
            backing_int_node,
            "non-packed struct does not support backing integer type",
            .{},
        );
        astgen.src_hasher.update(astgen.tree.getNodeSource(backing_int_node));
        const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node);
        if (!block_scope.endsWithNoReturn()) {
            _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
        }
        const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
        block_scope.instructions.items.len = block_scope.instructions_top;
        break :len body_len;
    } else null;

    var next_field_idx: u32 = 0;
    for (container_decl.ast.members) |member_node| {
        var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
            .decl => continue,
            .field => |field| field,
        };
        const field_idx = next_field_idx;
        next_field_idx += 1;

        astgen.src_hasher.update(tree.getNodeSource(member_node));

        member.convertToNonTupleLike(astgen.tree);
        assert(!member.ast.tuple_like);

        field_names.get(astgen)[field_idx] = @backingInt(try astgen.identAsString(member.ast.main_token));

        {
            const type_node = member.ast.type_expr.unwrap() orelse {
                return astgen.failTok(member.ast.main_token, "struct field missing type", .{});
            };
            const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_type_body_lens.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        }

        if (member.ast.align_expr.unwrap()) |align_node| {
            if (layout == .@"packed") {
                return astgen.failNode(align_node, "unable to override alignment of packed struct fields", .{});
            }
            const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_align_body_lens.?.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        } else if (field_align_body_lens) |lens| {
            lens.get(astgen)[field_idx] = 0;
        }

        if (member.ast.value_expr.unwrap()) |default_node| {
            const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
            const default_ref = try expr(&block_scope, &namespace.base, ri, default_node);
            if (!block_scope.endsWithNoReturn()) {
                _ = try block_scope.addBreak(.break_inline, decl_inst, default_ref);
            }
            const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
            field_default_body_lens.?.get(astgen)[field_idx] = body_len;
            block_scope.instructions.items.len = block_scope.instructions_top;
        } else if (field_default_body_lens) |lens| {
            lens.get(astgen)[field_idx] = 0;
        }

        if (member.comptime_token) |comptime_token| {
            switch (layout) {
                .@"packed", .@"extern" => return astgen.failTok(comptime_token, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
                .auto => {},
            }
            if (member.ast.value_expr == .none) {
                return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
            }
            const mask = @as(u32, 1) << @intCast(field_idx % 32);
            field_comptime_bits.?.get(astgen)[field_idx / 32] |= mask;
        }
    }
    assert(next_field_idx == scan_result.fields_len);
    wip_decls.finish();

    var fields_hash: std.zig.SrcHash = undefined;
    astgen.src_hasher.final(&fields_hash);

    try gz.setStruct(decl_inst, .{
        .src_line = src_line,
        .src_column = src_column,
        .src_node = node,
        .name_strat = name_strat,
        .layout = layout,
        .backing_int_type_body_len = backing_int_type_body_len,
        .decls_len = scan_result.decls_len,
        .fields_len = scan_result.fields_len,
        .any_field_aligns = scan_result.any_field_aligns,
        .any_field_defaults = scan_result.any_field_values,
        .any_comptime_fields = scan_result.any_comptime_fields,
        .fields_hash = fields_hash,
        .captures = namespace.captures.keys(),
        .capture_names = namespace.captures.values(),
        .remaining = scratch.all().get(astgen),
    });

    block_scope.unstack();
    return decl_inst.toRef();
}