NAME

Perl::Critic::Policy::ControlStructures::ProhibitBareBlockLoopControls - Prohibit unlabeled loop controls in non-loop blocks

VERSION

version 0.01

DESCRIPTION

Using next, last, or redo inside blocks that are not real loops (e.g. bare {} blocks, do {} blocks, anonymous subroutines, eval {}, map/grep blocks) leads to confusing or buggy behaviour:

  • Bare {} blocks are loops that execute once, so next and last both exit the block; next additionally runs any attached continue block.

  • do {} blocks are not loops — loop controls have no effect there.

  • Anonymous subroutines sub {} and eval {} are not loops either.

  • map {} / grep {} blocks are expression blocks — loop controls do not behave as expected.

EXAMPLES

Bare blocks ({ })

{
    next;           # not ok
}

{
    last;           # not ok
}

{
    last LOOP;      # ok
}

{
    redo;           # not ok
}

{
    redo LOOP;      # ok
}

do { } blocks

do {
    next;           # not ok
};

do {
    last LOOP;      # not ok (label does not help — do is not a loop)
};

Anonymous subroutines (sub { })

sub {
    next;           # not ok
};

sub {
    last LABEL;     # ok (if called from within a matching loop)
};

eval { } blocks

eval {
    last;           # not ok
};

map and grep blocks

map  { next; } @list;    # not ok
grep { redo; } @list;    # not ok

Real loops (always safe)

while (1) {
    next;                # ok
}

for my $x (@items) {
    last if $x eq 'foo'; # ok
}

foreach my $k (keys %h) {
    next;                # ok
}

CONFIGURATION

Each keyword next, last, redo can be set to one of:

forbid — always flag this keyword in non-loop blocks (default for next and redo)
require_label — flag unless the keyword has an explicit label (default for last)
allow — do not check this keyword at all

Block-type overrides (do_block, bare_block) can modify the behaviour for specific block types:

do_block: forbid (default) or follow per-keyword settings
bare_block: forbid, require_label (default), or follow per-keyword settings

Example .perlcriticrc:

[ControlStructures::ProhibitBareBlockLoopControls]
next        = forbid
last        = require_label
redo        = forbid
do_block    = forbid
bare_block  = require_label

SEE ALSO

"last" in perlfunc, "next" in perlfunc, "redo" in perlfunc, Perl::Critic::Policy::ControlStructures::ProhibitReturnInDoBlock

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