I ran into a situation where I can't inhibit warnings in an intuitive way because perl is in-lining a call to a built-in function. e.g.
use strict;
use warnings;
{
no warnings 'substr'; # no effect
foo(substr('123', 4, 6)); # out of range but shouldn't emit a warning
}
sub foo {
my $s = shift; # warning reported here
# do something
}
Running this code results in
substr outside of string at c:\temp\foo.pl line 10.
In order to inhibit the warning I have to move the no warnings 'substr'
inside the function.
sub foo {
no warnings 'substr'; # works here, but there's no call to substr
my $s = shift; # no warnings here
# do something
}
I can see that the call to substr
is being inlined by passing the code through perl -MO=Terse
LISTOP (0x27dcaa8) leave [1]
OP (0x27a402c) enter
COP (0x27dcac8) nextstate
BINOP (0x27dcb00) leaveloop
LOOP (0x27dcb20) enterloop
LISTOP (0x27dcb68) lineseq
COP (0x27dcb88) nextstate
UNOP (0x27dcbc0) entersub [5] # entry point for foo
UNOP (0x27dcbf4) null [148]
OP (0x27dcbdc) pushmark
LISTOP (0x27dcc48) substr [4] # substr gets called here
OP (0x27dcc30) null [3]
SVOP (0x27dcc84) const [6] PV (0x2319944) "123"
SVOP (0x27dcc68) const [7] IV (0x2319904) 4
SVOP (0x27dcc14) const [8] IV (0x231944c) 6
UNOP (0x27dcca0) null [17]
PADOP (0x27dccf4) gv GV (0x2318e5c) *foo
Is this optimizer behavior documented anywhere? perlsub
only mentions inlining of constant functions. Given that the warning is being reported on the wrong line and that no warnings
isn't working in the lexical scope where the call is being made I'm inclined to report this as a bug, although I can't think of how it could reasonably be fixed while preserving the optimization.
Note: This behavior was observed under Perl 5.16.1.
This is a documented behaviour (in perldiag):
substr outside of string
(W substr),(F) You tried to reference a substr() that pointed outside of a string. That is, the absolute value of the offset was larger than the length of the string. See "substr" in perlfunc. This warning is fatal if substr is used in an lvalue context (as the left hand side of an assignment or as a subroutine argument for example).
Emphasis mine.
Changing the call to
foo(my $o = substr('123', 4, 6));
makes the warnings disappear.
Moving the no warnings
into the sub doesn't change the behaviour for me. What Perl version do you have? (5.14.4 here).
The code I used for testing:
#!/usr/bin/perl
use strict;
use warnings;
$| = 1;
print 1, foo(my $s1 = substr('abc', 4, 6));
print 2, bar(my $s2 = substr('def', 4, 6));
{
no warnings 'substr';
print 3, foo(my $s3 = substr('ghi', 4, 6));
print 4, bar(my $s4 = substr('jkl', 4, 6));
print 5, bar(substr('mno', 4, 6)); # Stops here, reports line 12.
print 6, foo(substr('pqr', 4, 6));
}
print "ok\n";
sub foo {
my $s = shift;
}
sub bar {
no warnings 'substr';
my $s = shift;
}
I'm getting the same behaviour in 5.10.1, but in 5.20.1, the behaviour is as you described.
As you saw from B::Terse, the substr
is not inlined.
$ perl -MO=Concise,-exec -e'f(substr($_, 3, 4))'
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s
4 <#> gvsv[*_] s
5 <$> const[IV 3] s
6 <$> const[IV 4] s
7 <@> substr[t4] sKM/3 <-- The substr operator is evaluated first.
8 <#> gv[*f] s/EARLYCV
9 <1> entersub[t5] vKS/TARG <-- The sub call second.
a <@> leave[1 ref] vKP/REFC
-e syntax OK
When substr
is called as an lvalue context, substr
returns a magical scalar that contains the operands passed to substr
.
$ perl -MDevel::Peek -e'$_ = "abcdef"; Dump(${\ substr($_, 3, 4) })'
SV = PVLV(0x2865d60) at 0x283fbd8
REFCNT = 2
FLAGS = (GMG,SMG) <--- Gets and sets are magical.
IV = 0 GMG: A function that mods the scalar
NV = 0 is called before fetches.
PV = 0 SMG: A function is called after the
MAGIC = 0x2856810 scalar is modified.
MG_VIRTUAL = &PL_vtbl_substr
MG_TYPE = PERL_MAGIC_substr(x)
TYPE = x
TARGOFF = 3 <--- substr's second arg
TARGLEN = 4 <--- substr's third arg
TARG = 0x287bfd0 <--- substr's first arg
FLAGS = 0
SV = PV(0x28407f0) at 0x287bfd0 <--- A dump of substr's first arg
REFCNT = 2
FLAGS = (POK,IsCOW,pPOK)
PV = 0x2865d20 "abcdef"\0
CUR = 6
LEN = 10
COW_REFCNT = 1
Subroutine arguments are evaluated in lvalue context because subroutine arguments are always passed by reference in Perl[1].
$ perl -E'sub f { $_[0] = "def"; } $x = "abc"; f($x); say $x;'
def
The substring operation happens when the magical scalar is accessed.
$ perl -E'$x = "abc"; $r = \substr($x, 0, 1); $x = "def"; say $$r;'
d
This is done to allow substr(...) = "abc";
@_
are aliased to the subroutine arguments."If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With