diff options
-rw-r--r-- | embed.fnc | 3 | ||||
-rw-r--r-- | embed.h | 2 | ||||
-rw-r--r-- | ext/XS-APItest/APItest.xs | 9 | ||||
-rw-r--r-- | ext/XS-APItest/t/newCONSTSUB.t | 38 | ||||
-rw-r--r-- | op.c | 25 | ||||
-rw-r--r-- | proto.h | 2 |
6 files changed, 61 insertions, 18 deletions
@@ -877,7 +877,8 @@ Abm |CV* |newSUB |I32 floor|NULLOK OP* o|NULLOK OP* proto \ p |CV * |newXS_len_flags|NULLOK const char *name|STRLEN len \ |NN XSUBADDR_t subaddr\ |NN const char *const filename \ - |NULLOK const char *const proto|U32 flags + |NULLOK const char *const proto \ + |NULLOK SV **const_svp|U32 flags ApM |CV * |newXS_flags |NULLOK const char *name|NN XSUBADDR_t subaddr\ |NN const char *const filename \ |NULLOK const char *const proto|U32 flags @@ -1137,7 +1137,7 @@ #define my_stat_flags(a) Perl_my_stat_flags(aTHX_ a) #define my_swabn Perl_my_swabn #define my_unexec() Perl_my_unexec(aTHX) -#define newXS_len_flags(a,b,c,d,e,f) Perl_newXS_len_flags(aTHX_ a,b,c,d,e,f) +#define newXS_len_flags(a,b,c,d,e,f,g) Perl_newXS_len_flags(aTHX_ a,b,c,d,e,f,g) #define nextargv(a) Perl_nextargv(aTHX_ a) #define oopsAV(a) Perl_oopsAV(aTHX_ a) #define oopsHV(a) Perl_oopsHV(aTHX_ a) diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs index 46cc458d52..4f84c60d3e 100644 --- a/ext/XS-APItest/APItest.xs +++ b/ext/XS-APItest/APItest.xs @@ -1878,11 +1878,12 @@ call_method(methname, flags, ...) PUSHs(sv_2mortal(newSViv(i))); void -newCONSTSUB_type(stash, name, flags, type) +newCONSTSUB_type(stash, name, flags, type, sv) HV* stash SV* name I32 flags int type + SV* sv PREINIT: CV* cv; STRLEN len; @@ -1890,10 +1891,12 @@ newCONSTSUB_type(stash, name, flags, type) PPCODE: switch (type) { case 0: - cv = newCONSTSUB(stash, pv, NULL); + cv = newCONSTSUB(stash, pv, SvOK(sv) ? sv : NULL); break; case 1: - cv = newCONSTSUB_flags(stash, pv, len, flags | SvUTF8(name), NULL); + cv = newCONSTSUB_flags( + stash, pv, len, flags | SvUTF8(name), SvOK(sv) ? sv : NULL + ); break; } EXTEND(SP, 2); diff --git a/ext/XS-APItest/t/newCONSTSUB.t b/ext/XS-APItest/t/newCONSTSUB.t index b6e672d986..afd44262da 100644 --- a/ext/XS-APItest/t/newCONSTSUB.t +++ b/ext/XS-APItest/t/newCONSTSUB.t @@ -1,24 +1,46 @@ #!perl use strict; -use warnings; use utf8; use open qw( :utf8 :std ); -use Test::More tests => 11; +use Test::More tests => 14; use XS::APItest; -my ($const, $glob) = XS::APItest::newCONSTSUB_type(\%::, "sanity_check", 0, 0); +# This test must happen outside of any warnings scope +{ + local $^W; + my $w; + local $SIG{__WARN__} = sub { $w .= shift }; + sub frimple() { 78 } + newCONSTSUB_type(\%::, "frimple", 0, 1, undef); + like $w, qr/Constant subroutine frimple redefined at /, + 'newCONSTSUB constant redefinition warning is unaffected by $^W=0'; + undef $w; + newCONSTSUB_type(\%::, "frimple", 0, 1, undef); + is $w, undef, '...unless the const SVs are the same'; + eval 'sub frimple() { 78 }'; + undef $w; + newCONSTSUB_type(\%::, "frimple", 0, 1, "78"); + is $w, undef, '...or the const SVs have the same value'; +} + +use warnings; + +my ($const, $glob) = + XS::APItest::newCONSTSUB_type(\%::, "sanity_check", 0, 0, undef); ok $const; ok *{$glob}{CODE}; -($const, $glob) = XS::APItest::newCONSTSUB_type(\%::, "\x{30cb}", 0, 0); +($const, $glob) = + XS::APItest::newCONSTSUB_type(\%::, "\x{30cb}", 0, 0, undef); ok $const, "newCONSTSUB generates the constant,"; ok *{$glob}{CODE}, "..and the glob,"; ok !$::{"\x{30cb}"}, "...but not the right one"; -($const, $glob) = XS::APItest::newCONSTSUB_type(\%::, "\x{30cd}", 0, 1); +($const, $glob) = + XS::APItest::newCONSTSUB_type(\%::, "\x{30cd}", 0, 1, undef); ok $const, "newCONSTSUB_flags generates the constant,"; ok *{$glob}{CODE}, "..and the glob,"; ok $::{"\x{30cd}"}, "...the right one!"; @@ -29,7 +51,7 @@ eval q{ my $w; local $SIG{__WARN__} = sub { $w .= shift }; *foo = sub(){123}; - newCONSTSUB_type(\%::, "foo", 0, 1); + newCONSTSUB_type(\%::, "foo", 0, 1, undef); is $w, undef, 'newCONSTSUB uses calling scope for redefinition warnings'; } }; @@ -39,11 +61,11 @@ eval q{ *{"foo::\x{100}"} = sub(){return 123}; my $w; local $SIG{__WARN__} = sub { $w .= shift }; - newCONSTSUB_type(\%foo::, "\x{100}", 0, 1); + newCONSTSUB_type(\%foo::, "\x{100}", 0, 1, undef); like $w, qr/Subroutine \x{100} redefined at /, 'newCONSTSUB redefinition warning + utf8'; undef $w; - newCONSTSUB_type(\%foo::, "\x{100}", 0, 1); + newCONSTSUB_type(\%foo::, "\x{100}", 0, 1, 54); like $w, qr/Constant subroutine \x{100} redefined at /, 'newCONSTSUB constant redefinition warning + utf8'; } @@ -6961,7 +6961,7 @@ Perl_newCONSTSUB_flags(pTHX_ HV *stash, const char *name, STRLEN len, processor __FILE__ directive). But we need a dynamically allocated one, and we need it to get freed. */ cv = newXS_len_flags(name, len, const_sv_xsub, file ? file : "", "", - XS_DYNAMIC_FILENAME | flags); + &sv, XS_DYNAMIC_FILENAME | flags); CvXSUBANY(cv).any_ptr = sv; CvCONST_on(cv); @@ -6981,14 +6981,15 @@ Perl_newXS_flags(pTHX_ const char *name, XSUBADDR_t subaddr, { PERL_ARGS_ASSERT_NEWXS_FLAGS; return newXS_len_flags( - name, name ? strlen(name) : 0, subaddr, filename, proto, flags + name, name ? strlen(name) : 0, subaddr, filename, proto, NULL, flags ); } CV * Perl_newXS_len_flags(pTHX_ const char *name, STRLEN len, XSUBADDR_t subaddr, const char *const filename, - const char *const proto, U32 flags) + const char *const proto, SV **const_svp, + U32 flags) { CV *cv; @@ -7015,13 +7016,29 @@ Perl_newXS_len_flags(pTHX_ const char *name, STRLEN len, else if (CvROOT(cv) || CvXSUB(cv) || GvASSUMECV(gv)) { /* already defined (or promised) */ const char *redefined_name; - if (ckWARN(WARN_REDEFINE) + if (CvCONST(cv) && const_svp + && cv_const_sv(cv) == *const_svp) { + NOOP; + /* They are 2 constant subroutines generated from + the same constant. This probably means that + they are really the "same" proxy subroutine + instantiated in 2 places. Most likely this is + when a constant is exported twice. Don't warn. + */ + } + else if ((ckWARN(WARN_REDEFINE) && !( CvGV(cv) && GvSTASH(CvGV(cv)) && HvNAMELEN(GvSTASH(CvGV(cv))) == 7 && (redefined_name = HvNAME(GvSTASH(CvGV(cv))), strEQ(redefined_name, "autouse")) ) + ) + || (CvCONST(cv) + && ckWARN_d(WARN_REDEFINE) + && ( !const_svp + || sv_cmp(cv_const_sv(cv), *const_svp) ) + ) ) { const line_t oldline = CopLINE(PL_curcop); if (PL_parser && PL_parser->copline != NOLINE) @@ -2781,7 +2781,7 @@ PERL_CALLCONV CV * Perl_newXS_flags(pTHX_ const char *name, XSUBADDR_t subaddr, #define PERL_ARGS_ASSERT_NEWXS_FLAGS \ assert(subaddr); assert(filename) -PERL_CALLCONV CV * Perl_newXS_len_flags(pTHX_ const char *name, STRLEN len, XSUBADDR_t subaddr, const char *const filename, const char *const proto, U32 flags) +PERL_CALLCONV CV * Perl_newXS_len_flags(pTHX_ const char *name, STRLEN len, XSUBADDR_t subaddr, const char *const filename, const char *const proto, SV **const_svp, U32 flags) __attribute__nonnull__(pTHX_3) __attribute__nonnull__(pTHX_4); #define PERL_ARGS_ASSERT_NEWXS_LEN_FLAGS \ |