NAME

Perl::Critic::Policy::ControlStructures::LoopsRequireLabels - Require labels on loops and their break keywords

VERSION

version 0.01

DESCRIPTION

This policy requires loop-control keywords (next, last, redo) and the loops that contain them to carry explicit labels.

Labels make loop-control flow visible at a glance and prevent bugs when nested loops are added, removed, or reordered during refactoring.

EXAMPLES

mode=always

while (1) {
    next;           # not ok (loop + break both flagged)
}

LOOP:
while (1) {
    next LOOP;      # ok
}

LOOP:
while (1) {
    next;           # not ok (break inside labeled loop is bare)
}

while (1) {
    next OUTER;     # ok (break references a label even if loop lacks one)
}

mode=nested (default, max_lines=5)

while (1) {
    next;           # ok (top-level, body is 2 lines <= 5)
}

while (1) {
    while (1) {
        next;       # not ok (inner loop is nested)
    }
}

while (1) {
    INNER:
    while (1) {
        next;       # not ok (inner loop has label but break is bare)
    }
}

while (1) {
    INNER:
    while (1) {
        next INNER; # ok (inner loop labeled, break references it)
    }
}

while (1) {         # not ok (top-level but body is 6 lines > 5)
    print "a";
    print "b";
    print "c";
    next;
}

mode=max_lines, max_lines=3

while (1) {
    next;           # ok (body is 2 lines <= 3)
}

while (1) {         # not ok (body is 4 lines > 3)
    next;
    last;
}

while (1) {         # ok (body is 5 lines but no break keywords)
    print "hello";
    print "world";
}

Cascading labels through ancestor loops (non-configurable)

Regardless of the active mode, a bare break keyword is always flagged when any ancestor loop carries a label. This prevents ambiguity about which loop the keyword targets.

OUTER:
while (1) {
    while (1) {     # no label
        next;       # not ok (nearest loop unlabeled AND
                    #   OUTER has a label)
    }
}

OUTER:
while (1) {
    next OUTER;     # ok (break in outer references its label)
    last;           # not ok (outer has label but break is bare)

    INNER:
    while (1) {
        last OUTER; # ok (break references an outer label)
    }
}

continue blocks attached to a loop are treated as part of that loop for the purposes of this policy. Break keywords inside continue are subject to the same labeling rules as those in the main body.

Note that the max_lines line count considers only the main body block (from { to }). A long continue block does not by itself trigger the line-count threshold; only nesting or break keywords in the main body can do that.

while (1) {
    # no break keywords in the body
} continue {
    next;           # not ok (same rules apply here)
}

LOOP:
while (1) {
} continue {
    next LOOP;      # ok (break references the loop's label)
    last LOOP;      # ok
}

CONFIGURATION

Three modes control when labels are required:

always

Any loop that contains a next, last, or redo keyword must have a label, and those keywords must reference a label. The max_lines setting has no effect in this mode.

nested (default)

Labels are required when the loop is nested inside another real loop (for, foreach, while, or until). Additionally, regardless of nesting, labels are required if the loop body spans more than max_lines source lines (counting from { to } inclusive of the body block only; any attached continue block is not counted). This makes max_lines act as a safety net for long top-level loops. Set max_lines to a high value (e.g. 1000) to effectively disable the line-count check and rely on nesting alone.

max_lines

Labels are required when the loop body spans more than max_lines source lines (counting from { to } inclusive of the body block only; any attached continue block is not counted). Nesting is not considered. The threshold is configured with the max_lines parameter (default 30).

Example perlcriticrc:

# Built-in defaults (mode=nested, max_lines=30)
[ControlStructures::LoopsRequireLabels]

# Same defaults, written explicitly (default configuration)
[ControlStructures::LoopsRequireLabels]
mode      = nested
max_lines = 30

# Flag all loops with break keywords
[ControlStructures::LoopsRequireLabels]
mode = always

# Flag only by length, ignore nesting
[ControlStructures::LoopsRequireLabels]
mode      = max_lines
max_lines = 80

SEE ALSO

Perl::Critic, "last" in perlfunc, "next" in perlfunc, "redo" in perlfunc

AUTHOR

Dean Hamstead <dean@fragfest.com.au>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Dean Hamstead.

This is free software, licensed under:

The MIT (X11) License