Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions ListUtil.xs
Original file line number Diff line number Diff line change
Expand Up @@ -2027,3 +2027,19 @@ BOOT:
sv_setsv(rmcsv, &PL_sv_no);
#endif
}

PROTOTYPES: ENABLE

SV *
ROUTINE()
PREINIT:
CV *cv;
CODE:
cv = Perl_find_runcv(aTHX_ NULL);
if (CvUNIQUE(cv) && !CvSPECIAL(cv))
RETVAL = &PL_sv_undef;
else
RETVAL = newRV((SV*)cv);
OUTPUT:
RETVAL

22 changes: 22 additions & 0 deletions lib/Sub/Util.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,28 @@ $VERSION =~ tr/_//d;
require List::Util; # as it has the XS
List::Util->VERSION( $VERSION ); # Ensure we got the right XS version (RT#100863)

use constant CAN_SUB => $] >= 5.016;

use if CAN_SUB, feature => 'current_sub';

unless (CAN_SUB) {
push @EXPORT_OK, '__SUB__';
*__SUB__ = \&ROUTINE;
}

sub import {
my ($class, @args) = @_;
if (CAN_SUB) {
my @new_args = grep { $_ ne '__SUB__' } @args;
if (@args != @new_args) {
feature->import('current_sub');
@_ = ($class, @new_args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying @_ and then using goto causes segfaults on perl 5.8.4.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh; so we only do this for 5.8.5 and above and tell older users "sorry, no can do"

Copy link
Member

@haarg haarg Jun 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it doesn't matter - this code path is only for 5.16+. My comment can be ignored.

}
}

goto &Exporter::import;
}

=head1 NAME

Sub::Util - A selection of utility subroutines for subs and CODE references
Expand Down
108 changes: 108 additions & 0 deletions t/current_sub.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!perl

use strict;
use warnings;
use Test::More tests => 28;

use Sub::Util '__SUB__';

# basic.t

sub davros { __SUB__ }
is(davros(), \&davros, 'davros');

sub borusa {
my $coderef = __SUB__;
is($coderef, \&borusa, 'borusa');
}
borusa();

sub romana {
@_ = (__SUB__, \&romana, 'romana');
&is;
}
romana();

sub rassilon {
is(__SUB__, \&rassilon, 'rassilon');
}
rassilon();

# specialblocks.t

BEGIN { ok( defined __SUB__, "Don't point to BEGIN" ); }
CHECK { ok( defined __SUB__, "Don't point to CHECK" ); }
INIT { ok( defined __SUB__, "Don't point to INIT" ); }
END { ok( defined __SUB__, "Don't point to END" ); }

# autoload.t

sub AUTOLOAD {
is(__SUB__, \&AUTOLOAD, "AUTOLOAD $::AUTOLOAD");
}
sarah_jane();
leela();
sarah_jane(); # again

# main.t

ok( !defined __SUB__, "Don't point to main CV" );

# prototype.t

# polyfill prototype must be ''
ok( defined prototype \&Sub::Util::ROUTINE, 'proto defined' );
is( prototype \&Sub::Util::ROUTINE, '', 'proto empty' );

# and this should compile
sub skaro { __SUB__ }
is(skaro(), \&skaro, 'skaro');

# eval.t

sub runcible {
is(eval { __SUB__ }, \&runcible, "runcible");
}
runcible();

sub omega {
# eval("") is a special block context
ok(!defined eval q{ __SUB__ }, "omega");
}
omega();

sub master {
is(do { __SUB__ }, \&master, "master");
}
master();

# recurse.t

our $i = 0;
sub recurse {
if ($i++ < 4) {
ok(1, "test i$i");
__SUB__->();
}
}
recurse();

sub recurse2 {
my $j = shift;
if ($j > 0) {
ok(1, "test j$j");
__SUB__->($j - 1);
}
}
recurse2(4);

# anon.t

my $anon;
$anon = sub {
is(__SUB__, $anon, "anon sub");
};
$anon->();
my $copy = $anon;
$copy->();