内联内置文件的文档?

Documentation for inlining of built-ins?

我遇到了无法以直观方式抑制警告的情况,因为 perl 正在内联对内置函数的调用。例如

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
}

运行此代码会导致

substr outside of string at c:\temp\foo.pl line 10.

为了禁止警告,我必须将 no warnings 'substr' 移到函数内部。

sub foo {
    no warnings 'substr'; # works here, but there's no call to substr
    my $s = shift;        # no warnings here
    # do something
}

我可以看到,通过 perl -MO=Terse

传递代码,正在内联对 substr 的调用
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

是否在任何地方记录了此优化器行为? perlsub 只提到常量函数的内联。鉴于警告是在错误的行上报告的,并且 no warnings 在进行调用的词法范围内不起作用,我倾向于将其报告为错误,尽管我想不出如何在保持优化的同时合理地修复它。

注意:此行为是在 Perl 5.16.1 下观察到的。

这是记录在案的行为(在 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).

强调我的。

将电话改为

foo(my $o = substr('123', 4, 6));

使警告消失。

no warnings 移动到 sub 中不会改变我的行为。你有什么 Perl 版本? (此处为 5.14.4)。

我用来测试的代码:

#!/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;
}

更新:

我在 5.10.1 中得到了相同的行为,但在 5.20.1 中,行为与您描述的一样。

如您在 B::Terse 中所见,substr 未内联。

$ 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

substr 作为左值上下文调用时,substr returns 包含传递给 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"[=11=]
    CUR = 6
    LEN = 10
    COW_REFCNT = 1

子程序参数在左值上下文中计算,因为在 Perl 中子程序参数总是通过引用传递[1].

$ perl -E'sub f { $_[0] = "def"; }  $x = "abc"; f($x); say $x;'
def

访问神奇标量时发生子字符串操作。

$ perl -E'$x = "abc"; $r = \substr($x, 0, 1); $x = "def"; say $$r;'
d

这样做是为了让substr(...) = "abc";


  1. 这可能是使用类似于以下的语言记录的:"The elements of @_ are aliased to the subroutine arguments."