NAME
Perl::Critic::Policy::ControlStructures::ProhibitBareBlockLoopControls - Prohibit unlabeled loop controls in non-loop blocks
VERSION
version 0.06
DESCRIPTION
This policy flags next, last, and redo when used inside blocks that are not real loops or where their loop-control semantics are surprising (bare {} blocks, do {} blocks, anonymous subroutines, eval {}, map/grep).
The hazards fall into two distinct categories.
Bare {} blocks (real loops with surprising semantics)
Bare {} blocks are real loops -- next, last, and redo work correctly within them. The danger is that readers often do not recognise a bare block as a looping construct:
A bare block executes exactly once, so
nextexits the block (it does not restart it).lastalso exits;redore-executes the single pass and skips any code that would follow.Inside a real loop, an unlabeled
next/last/redotargets the bare block, not the outer loop. This is almost always unintentional and can mask subtle bugs when the block is added during refactoring.A
continueblock attached to a bare block runs afternext, which further surprises readers who think of the block as a one-shot scope.
Non-loop constructs (controls leak or fail at runtime)
do {}, sub {}, eval {}, map {}, and grep {} are not loops. Loop controls inside them either leak to an enclosing real loop or cause a runtime error:
do {},sub {},eval {}-- the control escapes to the nearest enclosing real loop (Perl emits"Exiting %s via %s"at thewarningslevel). If no enclosing loop exists, Perl dies withCan't "%s" outside a loop block.map {}/grep {}-- these are iteration constructs (the block runs once per element, just likefor my $x (@list)), but they are not loop-control targets.nextdoes not skip to the next map element; it escapes to the nearest enclosing real loop (or is a runtime error). Use an explicitforloop when you need loop control.
The default policy depends on both the keyword and the enclosing block type:
Keyword bare C<{}> C<do {}>
------------------------------------------------
last require_label forbid
next forbid forbid
redo forbid forbid
EXAMPLES
The following examples illustrate the default configuration.
Bare blocks ({ })
{
next; # not ok
}
FOO: {
next FOO; # not ok
}
{
last; # not ok
}
BAR: {
last BAR; # ok
}
{
redo; # not ok
}
BAZ: {
redo BAZ; # not ok
}
Bare blocks inside real loops
for my $x (@items) {
{
next; # not ok
}
}
for my $x (@items) {
FOO: {
next FOO; # not ok
}
}
BAR:
for my $x (@items) {
{
next BAR; # ok (targets the outer real loop)
}
}
do { } blocks
do {
next; # not ok - fatal error at runtime (no enclosing loop)
};
while (1) {
do {
next; # not ok - exits the while, not the do (action-at-a-distance)
};
}
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 - fatal error at runtime (no enclosing loop)
while (<$fh>) {
my @words = map { last; } split; # not ok - exits the while, not the map
}
grep { redo; } @list; # not ok
Use a for loop when you need loop control:
for my $elem (@list) {
next if cond($elem); # 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 fornextandredo)require_label-- flag unless the keyword has an explicit label (default forlast)allow-- do not check this keyword at all in non-loop blocks-
These per-keyword defaults apply when no block-type override is in effect (or the override is set to
follow; see below).
Block-type overrides (do_block, bare_block) can modify the behaviour for specific block types:
bare_block:forbid,require_label, orfollow(default) per-keyword settingsdo_block:forbid(default),require_label, orfollowper-keyword settings
Bare blocks are real loops (they execute once), so labeled controls work correctly. The default is follow, which defers to the per-keyword setting for each keyword: last requires a label, next and redo are always flagged. do blocks are not loops at all, so controls are forbidden entirely by default; require_label allows them when an outer loop is the intended target.
Example perlcriticrc:
[ControlStructures::ProhibitBareBlockLoopControls]
next = forbid
last = require_label
redo = forbid
do_block = forbid
bare_block = follow
Note: This is the default configuration.
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