NAME

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

VERSION

version 0.05

DESCRIPTION

This policy flags next, last, and redo when used inside blocks that are not real loops or where control flow is confusing (bare {} blocks, do {} blocks, anonymous subroutines, eval {}, map/grep).

Why these blocks are problematic:

  • 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 -- control keywords target the nearest enclosing real loop instead of the do block itself.

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

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

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
};

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 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, or follow (default) per-keyword settings
do_block: forbid (default), require_label, or follow per-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