# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling)
#endif
+#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser)
+# ifndef PL_error_count
+# define PL_error_count PL_parser->error_count
+# endif
+#else
+# ifndef PL_error_count
+# define PL_error_count PL_Ierror_count
+# endif
+#endif
+
/* uvar magic and Hash::Util::FieldHash were commited with 28419 */
#if VMG_HAS_PERL_MAINT(5, 9, 4, 28419) || VMG_HAS_PERL(5, 10, 0)
# define VMG_UVAR 1
#define vmg_data_new(C, S, A) vmg_data_new(aTHX_ (C), (S), (A))
SV *nsv;
I32 i, alen = (args == NULL) ? 0 : av_len(args);
- I32 flags = G_SCALAR;
dSP;
- int count;
ENTER;
SAVETMPS;
PUSHs(*av_fetch(args, i, 0));
PUTBACK;
- if (IN_PERL_COMPILETIME)
- flags |= G_EVAL | G_KEEPERR;
-
- count = call_sv(ctor, flags);
+ call_sv(ctor, G_SCALAR);
SPAGAIN;
- if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
nsv = POPs;
#if VMG_HAS_PERL(5, 8, 3)
SvREFCNT_inc(nsv); /* Or it will be destroyed in FREETMPS */
/* ... svt callbacks ....................................................... */
-STATIC int vmg_cb_call(pTHX_ SV *cb, SV *sv, SV *data, unsigned int args, ...) {
+#define VMG_CB_CALL_ARGS_MASK 15
+#define VMG_CB_CALL_EVAL 16
+
+STATIC int vmg_cb_call(pTHX_ SV *cb, SV *sv, SV *data, unsigned int flags, ...){
va_list ap;
SV *svr;
int ret;
unsigned int i;
- I32 flags = G_SCALAR;
+ unsigned int args = flags & VMG_CB_CALL_ARGS_MASK;
+ unsigned int eval = flags & VMG_CB_CALL_EVAL ? G_EVAL : 0;
dSP;
- int count;
ENTER;
SAVETMPS;
EXTEND(SP, args + 2);
PUSHs(sv_2mortal(newRV_inc(sv)));
PUSHs(data ? data : &PL_sv_undef);
- va_start(ap, args);
+ va_start(ap, flags);
for (i = 0; i < args; ++i) {
SV *sva = va_arg(ap, SV *);
PUSHs(sva ? sva : &PL_sv_undef);
va_end(ap);
PUTBACK;
- if (IN_PERL_COMPILETIME)
- flags |= G_EVAL | G_KEEPERR;
-
- count = call_sv(cb, flags);
+ call_sv(cb, G_SCALAR | eval);
SPAGAIN;
-
- if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
+ if (eval && IN_PERL_COMPILETIME && SvTRUE(ERRSV))
+ ++PL_error_count;
svr = POPs;
ret = SvOK(svr) ? SvIV(svr) : 0;
-
PUTBACK;
FREETMPS;
LEAVE;
+
return ret;
}
#define vmg_cb_call1(I, S, D) vmg_cb_call(aTHX_ (I), (S), (D), 0)
+#define vmg_cb_call1e(I, S, D) vmg_cb_call(aTHX_ (I), (S), (D), VMG_CB_CALL_EVAL)
#define vmg_cb_call2(I, S, D, S2) vmg_cb_call(aTHX_ (I), (S), (D), 1, (S2))
#define vmg_cb_call3(I, S, D, S2, S3) vmg_cb_call(aTHX_ (I), (S), (D), 2, (S2), (S3))
SV *svr;
I32 len, has_array;
U32 ret;
- I32 flags = G_SCALAR;
dSP;
int count;
}
PUTBACK;
- if (IN_PERL_COMPILETIME)
- flags |= G_EVAL | G_KEEPERR;
-
- count = call_sv(SV2MGWIZ(mg->mg_ptr)->cb_len, flags);
+ count = call_sv(SV2MGWIZ(mg->mg_ptr)->cb_len, G_SCALAR);
SPAGAIN;
-
- if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
svr = POPs;
ret = SvOK(svr) ? SvUV(svr) : len;
-
PUTBACK;
FREETMPS;
#endif
/* Perl_mg_free will get rid of the magic and decrement mg->mg_obj and
* mg->mg_ptr reference count */
- return vmg_cb_call1(SV2MGWIZ(mg->mg_ptr)->cb_free, sv, mg->mg_obj);
+ return vmg_cb_call1e(SV2MGWIZ(mg->mg_ptr)->cb_free, sv, mg->mg_obj);
}
#if MGf_COPY
@callers = ();
my $u = $b;
is_deeply(\@callers, [
- [ 'main', $0, __LINE__-2 ]
+ [ 'main', $0, __LINE__-2 ],
], 'caller into callback into block returns the right thing');
}
eval { my $u = $b };
is($@, '', 'caller into callback doesn\'t croak');
is_deeply(\@callers, [
- [ 'main', $0, __LINE__-3 ],
- [ 'main', $0, __LINE__-4 ],
+ ([ 'main', $0, __LINE__-3 ]) x 2,
], 'caller into callback into eval returns the right thing');
use strict;
use warnings;
-use Test::More tests => 1;
+use Test::More tests => 7;
-use Variable::Magic qw/wizard cast getdata/;
+use Variable::Magic qw/wizard cast/;
+
+my $wiz;
+
+eval {
+ $wiz = wizard data => sub { $_[1]->() };
+ my $x;
+ cast $x, $wiz, sub { die "carrot" };
+};
+
+like $@, qr/carrot/, 'die in data callback';
+
+eval {
+ $wiz = wizard data => sub { $_[1] },
+ set => sub { $_[1]->(); () };
+ my $x;
+ cast $x, $wiz, sub { die "lettuce" };
+ $x = 5;
+};
+
+like $@, qr/lettuce/, 'die in set callback';
+
+my $res = eval {
+ $wiz = wizard data => sub { $_[1] },
+ len => sub { $_[1]->(); () };
+ my @a = (1 .. 3);
+ cast @a, $wiz, sub { die "potato" };
+ @a;
+};
+
+like $@, qr/potato/, 'die in len callback';
+
+eval {
+ $wiz = wizard data => sub { $_[1] },
+ free => sub { $_[1]->(); () };
+ my $x;
+ cast $x, $wiz, sub { die "spinach" };
+};
+
+like $@, qr/spinach/, 'die in free callback';
# Inspired by B::Hooks::EndOfScope
-# This test is better be left at the beginning of the file, since problems
-# happen at UNITCHECK time
-my $wiz;
+eval q{BEGIN {
+ $wiz = wizard data => sub { $_[1]->() };
+ my $x;
+ cast $x, $wiz, sub { die "pumpkin" };
+}};
-BEGIN {
- $wiz = wizard data => sub { $_[1] }, free => sub { $_[1]->(); () };
+like $@, qr/pumpkin/, 'die in data callback in BEGIN';
+
+eval q{BEGIN {
+ $wiz = wizard data => sub { $_[1] },
+ free => sub { $_[1]->(); () };
$^H |= 0x020000;
- cast %^H, $wiz, sub { die "harmless" };
-}
+ cast %^H, $wiz, sub { die "macaroni" };
+}};
+
+like $@, qr/macaroni/, 'die in free callback in BEGIN';
+
+eval q{BEGIN {
+ $wiz = wizard data => sub { $_[1] },
+ len => sub { $_[1]->(); $_[2] },
+ free => sub { my $x = @{$_[0]}; () };
+ my @a = (1 .. 5);
+ cast @a, $wiz, sub { die "pepperoni" };
+}};
-pass 'die in free callback in BEGIN didn\'t segfault';
+like $@, qr/pepperoni/, 'die in len callback in BEGIN';