detect sub attributes following a signature
authorDavid Mitchell <davem@iabyn.com>
Mon, 26 Feb 2018 18:52:23 +0000 (18:52 +0000)
committerDavid Mitchell <davem@iabyn.com>
Fri, 2 Mar 2018 13:36:43 +0000 (13:36 +0000)
commita8c5635617479436b1775ba4ab34e4bc791eda54
tree870dda66a262326c7e359e6c8fd7d45383b39867
parent86ae8d9a6f56e9e71efc1f3e556f6770dc07566e
detect sub attributes following a signature

RT #132760

A recent commit (v5.27.7-212-g894f226) moved subroutine attributes back
before the subroutine's signature: e.g.

    sub foo :prototype($$) ($a, $b) { ... }  # 5.18 and 5.28 +
    sub foo ($a, $b) :prototype($$) { ... }  # 5.20 .. 5.26

This change means that any code still using an attribute following the
signature is going to trigger a syntax error. However, the error, followed
by error recovery and further warnings and errors, is very unfriendly and
gives no indication of the root cause. This commit introduces a new error,
"Subroutine attributes must come before the signature".

For example, List::Lazy, the subject of the ticket, failed to compile
tests, with output like:

    Array found where operator expected at blib/lib/List/Lazy.pm line 43,
    near "$$@)" (Missing operator before @)?)
    "my" variable $step masks earlier declaration in same statement at
    blib/lib/List/Lazy.pm line 44.
    syntax error at blib/lib/List/Lazy.pm line 36, near ") :"
    Global symbol "$generator" requires explicit package name (did you
    forget to declare "my $generator"?) at blib/lib/List/Lazy.pm line 38.
    Global symbol "$state" requires explicit package name (did you forget
    to declare "my $state"?) at blib/lib/List/Lazy.pm line 39.
    Global symbol "$min" requires explicit package name (did you forget to
    declare "my $min"?) at blib/lib/List/Lazy.pm line 43.
    Global symbol "$max" requires explicit package name (did you forget to
    declare "my $max"?) at blib/lib/List/Lazy.pm line 43.
    Global symbol "$step" requires explicit package name (did you forget
    to declare "my $step"?) at blib/lib/List/Lazy.pm line 43.
    Invalid separator character '{' in attribute list at
    blib/lib/List/Lazy.pm line 44, near "$step : sub "
    Global symbol "$step" requires explicit package name (did you forget
    to declare "my $step"?) at blib/lib/List/Lazy.pm line 44.

But following this commit, it now just outputs:

    Subroutine attributes must come before the signature at
    blib/lib/List/Lazy.pm line 36.
    Compilation failed in require at t/append.t line 5.
    BEGIN failed--compilation aborted at t/append.t line 5.

It works by:

1) adding a boolean flag (sig_seen) to the parser state to indicate that a
   signature has been parsed;
2) at the end of parsing a signature, PL_expect is set to XATTRBLOCK
   rather than XBLOCK.

Then if something looking like one or more attributes is encountered
by the lexer immediately afterwards, it scans it as if it were an
attribute, but then if sig_seen is true, it croaks.
parser.h
perly.act
perly.h
perly.tab
perly.y
pod/perldiag.pod
t/op/signatures.t
toke.c