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

continueExpr

Private Function
std.zig.AstGen.continueExpr
fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref

Params

Errors

OutOfMemory
AnalysisFail

File

zig/AstGen.zig:2256
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
    const astgen = parent_gz.astgen;
    const tree = astgen.tree;
    const opt_break_label, const opt_rhs = tree.nodeData(node).opt_token_and_opt_node;

    if (opt_break_label == .none and opt_rhs != .none) {
        return astgen.failNode(node, "cannot continue with operand without label", .{});
    }

    // Look for the label in the scope.
    find_scope: switch (parent_scope.unwrap()) {
        .gen_zir => |gen_zir| {
            const scope = &gen_zir.base;

            if (gen_zir.cur_defer_node.unwrap()) |cur_defer_node| {
                return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{
                    try astgen.errNoteNode(
                        cur_defer_node,
                        "defer expression here",
                        .{},
                    ),
                });
            }

            if (opt_break_label.unwrap()) |break_label| labeled: {
                if (gen_zir.label) |*label| {
                    if (try astgen.tokenIdentEql(label.token, break_label)) {
                        switch (gen_zir.continue_target) {
                            .none => {
                                return astgen.failNode(node, "continue outside of loop or labeled switch expression", .{});
                            },
                            .@"break" => if (opt_rhs != .none) {
                                return astgen.failNode(node, "cannot continue loop with operand", .{});
                            },
                            .switch_continue => if (opt_rhs == .none) {
                                return astgen.failNode(node, "cannot continue switch without operand", .{});
                            },
                        }
                        label.used = true;
                        label.used_for_continue = true;
                        break :labeled;
                    }
                }
                // gz without or with different label, continue to parent scopes.
                continue :find_scope gen_zir.parent.unwrap();
            } else if (gen_zir.allow_unlabeled_control_flow) {
                // This `continue` is unlabeled. If the gz we've found doesn't
                // provide a `continue` target or corresponds to a labeled
                // `switch`, ignore it and continue to parent scopes.
                switch (gen_zir.continue_target) {
                    .none, .switch_continue => {
                        continue :find_scope gen_zir.parent.unwrap();
                    },
                    .@"break" => {},
                }
            } else {
                // We don't have a break label and the gz we found doesn't allow
                // unlabeled control flow, so we continue to its parent scopes.
                continue :find_scope gen_zir.parent.unwrap();
            }

            switch (gen_zir.continue_target) {
                .none => unreachable, // should have failed or continued to parent scopes by now
                .@"break" => |block| {
                    try genDefers(parent_gz, scope, parent_scope, .normal_only);

                    const break_tag: Zir.Inst.Tag = if (gen_zir.is_inline)
                        .break_inline
                    else
                        .@"break";
                    if (break_tag == .break_inline) {
                        _ = try parent_gz.addUnNode(.check_comptime_control_flow, block.toRef(), node);
                    }

                    // As our last action before the continue, "pop" the error trace if needed
                    if (!gen_zir.is_comptime) {
                        _ = try parent_gz.addRestoreErrRetIndex(.{ .block = block }, .always, node);
                    }
                    _ = try parent_gz.addBreak(break_tag, block, .void_value);
                    return .unreachable_value;
                },
                .switch_continue => |switch_block| {
                    const rhs = opt_rhs.unwrap().?; // checked above
                    const operand = try reachableExpr(parent_gz, parent_scope, gen_zir.continue_result_info, rhs, node);

                    try genDefers(parent_gz, scope, parent_scope, .normal_only);

                    // As our last action before the continue, "pop" the error trace if needed
                    if (!gen_zir.is_comptime) {
                        _ = try parent_gz.addRestoreErrRetIndex(.{ .block = switch_block }, .always, node);
                    }
                    _ = try parent_gz.addBreakWithSrcNode(.switch_continue, switch_block, operand, rhs);
                    return .unreachable_value;
                },
            }
        },
        .local_val => |local_val| continue :find_scope local_val.parent.unwrap(),
        .local_ptr => |local_ptr| continue :find_scope local_ptr.parent.unwrap(),
        .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
        .namespace => {
            if (opt_break_label.unwrap()) |break_label| {
                const label_name = try astgen.identifierTokenString(break_label);
                return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
            } else {
                return astgen.failNode(node, "continue expression outside loop", .{});
            }
        },
        .top => unreachable,
    }
}