summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--op.c58
-rw-r--r--pod/perldiag.pod7
-rw-r--r--t/op/blocks.t29
3 files changed, 74 insertions, 20 deletions
diff --git a/op.c b/op.c
index 9de2326488..47c78bfcbd 100644
--- a/op.c
+++ b/op.c
@@ -10231,6 +10231,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
bool has_name;
bool name_is_utf8 = o && !o_is_gv && SvUTF8(cSVOPo->op_sv);
bool evanescent = FALSE;
+ bool isBEGIN = FALSE;
OP *start = NULL;
#ifdef PERL_DEBUG_READONLY_OPS
OPSLAB *slab = NULL;
@@ -10283,6 +10284,36 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
}
}
+ if (o)
+ SAVEFREEOP(o);
+ if (proto)
+ SAVEFREEOP(proto);
+ if (attrs)
+ SAVEFREEOP(attrs);
+
+ /* we need this in two places later on, so set it up here */
+ if (name && block) {
+ const char *s = (char *) my_memrchr(name, ':', namlen);
+ s = s ? s+1 : name;
+ isBEGIN = strEQ(s,"BEGIN");
+ }
+
+ if (isBEGIN) {
+ /* Make sure that we do not have any prototypes or
+ * attributes associated with this BEGIN block, as the block
+ * is already done and dusted, and we will assert or worse
+ * if we try to attach the prototype to the now essentially
+ * nonexistent sub. */
+ if (proto)
+ /* diag_listed_as: %s on BEGIN block ignored */
+ Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Prototype on BEGIN block ignored");
+ if (attrs)
+ /* diag_listed_as: %s on BEGIN block ignored */
+ Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Attribute on BEGIN block ignored");
+ proto = NULL;
+ attrs = NULL;
+ }
+
if (proto) {
assert(proto->op_type == OP_CONST);
ps = SvPV_const(cSVOPx(proto)->op_sv, ps_len);
@@ -10291,13 +10322,6 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
else
ps = NULL;
- if (o)
- SAVEFREEOP(o);
- if (proto)
- SAVEFREEOP(proto);
- if (attrs)
- SAVEFREEOP(attrs);
-
if (ec) {
op_free(block);
@@ -10307,18 +10331,14 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
cv = PL_compcv;
PL_compcv = 0;
- if (name && block) {
- const char *s = (char *) my_memrchr(name, ':', namlen);
- s = s ? s+1 : name;
- if (strEQ(s, "BEGIN")) {
- if (PL_in_eval & EVAL_KEEPERR)
- Perl_croak_nocontext("BEGIN not safe after errors--compilation aborted");
- else {
- SV * const errsv = ERRSV;
- /* force display of errors found but not reported */
- sv_catpvs(errsv, "BEGIN not safe after errors--compilation aborted");
- Perl_croak_nocontext("%" SVf, SVfARG(errsv));
- }
+ if (isBEGIN) {
+ if (PL_in_eval & EVAL_KEEPERR)
+ Perl_croak_nocontext("BEGIN not safe after errors--compilation aborted");
+ else {
+ SV * const errsv = ERRSV;
+ /* force display of errors found but not reported */
+ sv_catpvs(errsv, "BEGIN not safe after errors--compilation aborted");
+ Perl_croak_nocontext("%" SVf, SVfARG(errsv));
}
}
goto done;
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index 60df382646..e513bb0b8c 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -5249,6 +5249,13 @@ the sub name and via the prototype attribute. The prototype in
parentheses is useless, since it will be replaced by the prototype
from the attribute before it's ever used.
+=item %s on BEGIN block ignored
+
+(W syntax) C<BEGIN> blocks are executed immediately after they are parsed
+and then thrown away. Any prototypes or attributes are therefore
+meaningless and are ignored. You should remove them from the C<BEGIN> block.
+Note this also means you cannot create a constant called C<BEGIN>.
+
=item Quantifier follows nothing in regex; marked by S<<-- HERE> in m/%s/
(F) You started a regular expression with a quantifier. Backslash it if
diff --git a/t/op/blocks.t b/t/op/blocks.t
index 18f0596226..33401bdaf6 100644
--- a/t/op/blocks.t
+++ b/t/op/blocks.t
@@ -6,7 +6,7 @@ BEGIN {
set_up_inc('../lib');
}
-plan tests => 23;
+plan tests => 26;
my @expect = qw(
b1
@@ -253,6 +253,33 @@ fresh_perl_like(
"INIT{die} should exit"
);
+fresh_perl_is(
+ "BEGIN{} BEGIN(){1} print 'done'",
+ "Prototype on BEGIN block ignored at - line 1.\ndone",
+ {},
+ "Prototypes on BEGIN blocks should warn"
+);
+
+SKIP: {
+ skip "Test requires full perl, this is miniperl", 1
+ if is_miniperl;
+
+ fresh_perl_is(
+ "use attributes; BEGIN{} sub BEGIN :blerg {1} print 'done'",
+ "Attribute on BEGIN block ignored at - line 1.\ndone",
+ {},
+ "Attributes on BEGIN blocks should warn"
+ );
+}
+
+fresh_perl_is(
+ 'BEGIN() {10} foreach my $p (sort {lc($a) cmp lc($b)} keys %v)',
+ "Prototype on BEGIN block ignored at - line 1.\n"
+ . "syntax error at - line 1, at EOF\n"
+ . "Execution of - aborted due to compilation errors.",
+ {},
+ "Prototype on BEGIN blocks should warn"
+);
TODO: {
local $TODO = 'RT #2917: INIT{} in eval is wrongly considered too late';