diff options
author | David Mitchell <davem@iabyn.com> | 2010-12-15 19:38:17 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2010-12-15 19:41:46 +0000 |
commit | a42d02426c51c2ef1bdefac84284a828de703cda (patch) | |
tree | ff6b50dda007214dc0ed829f064c3db7723071c7 | |
parent | c2f8ff19c9ed44116de94b8779bfd09751377cd8 (diff) | |
download | perl-a42d02426c51c2ef1bdefac84284a828de703cda.tar.gz |
don't upgrade overload IV return values to NV
(if we can avoid it).
Fix for RT #77456. Basically it extends the usage of the AMGf_numeric flag
to the remaining overloadable numeric ops that behave differently with IV
and NV.
-rw-r--r-- | lib/overload64.t | 62 | ||||
-rw-r--r-- | pp.c | 18 | ||||
-rw-r--r-- | pp_hot.c | 2 |
3 files changed, 71 insertions, 11 deletions
diff --git a/lib/overload64.t b/lib/overload64.t index f4b0cb050f..f11f8598bc 100644 --- a/lib/overload64.t +++ b/lib/overload64.t @@ -11,7 +11,7 @@ BEGIN { } $| = 1; -use Test::More 'tests' => 100; +use Test::More 'tests' => 140; my $ii = 36028797018963971; # 2^55 + 3 @@ -213,4 +213,64 @@ is($$oo, $cnt++, 'overload called once'); is($oo**1, $ii, '** overload'); is($$oo, $cnt++, 'overload called once'); +# RT #77456: when conversion method returns an IV/UV, +# avoid IV -> NV upgrade if possible . + +{ + package P77456; + use overload '0+' => sub { $_[0][0] }, fallback => 1; + + package main; + + for my $expr ( + '(%531 + 1) - $a531 == 1', # pp_add + '$a531 - (%531 - 1) == 1', # pp_subtract + '(%531 * 2 + 1) - (%531 * 2) == 1', # pp_multiply + '(%54 / 2 + 1) - (%54 / 2) == 1', # pp_divide + '(%271 ** 2 + 1) - (%271 ** 2) == 1', # pp_pow + '(%541 % 2) == 1', # pp_modulo + '$a54 + (-%531)*2 == -2', # pp_negate + '(abs(%53m)+1) - $a53 == 1', # pp_abs + '(%531 << 1) - 2 == $a54', # pp_left_shift + '(%541 >> 1) + 1 == $a531', # pp_right_shift + '!(%53 == %531)', # pp_eq + '(%53 != %531)', # pp_ne + '(%53 < %531)', # pp_lt + '!(%531 <= %53)', # pp_le + '(%531 > %53)', # pp_gt + '!(%53 >= %531)', # pp_ge + '(%53 <=> %531) == -1', # pp_ncmp + '(%531 & %53) == $a53', # pp_bit_and + '(%531 | %53) == $a531', # pp_bit_or + '~(~ %531 + $a531) == 0', # pp_complement + ) { + for my $int ('', 'use integer; ') { + (my $aexpr = "$int$expr") =~ s/\%(\d+m?)/\$a$1/g; + (my $bexpr = "$int$expr") =~ s/\%(\d+m?)/\$b$1/g; + + my $a27 = 1 << 27; + my $a271 = $a27 + 1; + my $a53 = 1 << 53; + my $a53m = -$a53; + my $a531 = $a53 + 1; + my $a54 = 1 << 54; + my $a541 = $a54 + 1; + + my $b27 = bless [ $a27 ], 'P77456'; + my $b271 = bless [ $a271 ], 'P77456'; + my $b53 = bless [ $a53 ], 'P77456'; + my $b53m = bless [ $a53m ], 'P77456'; + my $b531 = bless [ $a531 ], 'P77456'; + my $b54 = bless [ $a54 ], 'P77456'; + my $b541 = bless [ $a541 ], 'P77456'; + + SKIP: { + skip("IV/NV not suitable on this platform: $aexpr", 1) + unless eval $aexpr; + ok(eval $bexpr, "IV: $bexpr"); + } + } + } +} + # EOF @@ -1795,7 +1795,7 @@ PP(pp_subtract) PP(pp_left_shift) { dVAR; dSP; dATARGET; SV *svl, *svr; - tryAMAGICbin_MG(lshift_amg, AMGf_assign); + tryAMAGICbin_MG(lshift_amg, AMGf_assign|AMGf_numeric); svr = POPs; svl = TOPs; { @@ -1815,7 +1815,7 @@ PP(pp_left_shift) PP(pp_right_shift) { dVAR; dSP; dATARGET; SV *svl, *svr; - tryAMAGICbin_MG(rshift_amg, AMGf_assign); + tryAMAGICbin_MG(rshift_amg, AMGf_assign|AMGf_numeric); svr = POPs; svl = TOPs; { @@ -1835,7 +1835,7 @@ PP(pp_right_shift) PP(pp_lt) { dVAR; dSP; - tryAMAGICbin_MG(lt_amg, AMGf_set); + tryAMAGICbin_MG(lt_amg, AMGf_set|AMGf_numeric); #ifdef PERL_PRESERVE_IVUV SvIV_please_nomg(TOPs); if (SvIOK(TOPs)) { @@ -1918,7 +1918,7 @@ PP(pp_lt) PP(pp_gt) { dVAR; dSP; - tryAMAGICbin_MG(gt_amg, AMGf_set); + tryAMAGICbin_MG(gt_amg, AMGf_set|AMGf_numeric); #ifdef PERL_PRESERVE_IVUV SvIV_please_nomg(TOPs); if (SvIOK(TOPs)) { @@ -2002,7 +2002,7 @@ PP(pp_gt) PP(pp_le) { dVAR; dSP; - tryAMAGICbin_MG(le_amg, AMGf_set); + tryAMAGICbin_MG(le_amg, AMGf_set|AMGf_numeric); #ifdef PERL_PRESERVE_IVUV SvIV_please_nomg(TOPs); if (SvIOK(TOPs)) { @@ -2086,7 +2086,7 @@ PP(pp_le) PP(pp_ge) { dVAR; dSP; - tryAMAGICbin_MG(ge_amg,AMGf_set); + tryAMAGICbin_MG(ge_amg,AMGf_set|AMGf_numeric); #ifdef PERL_PRESERVE_IVUV SvIV_please_nomg(TOPs); if (SvIOK(TOPs)) { @@ -2170,7 +2170,7 @@ PP(pp_ge) PP(pp_ne) { dVAR; dSP; - tryAMAGICbin_MG(ne_amg,AMGf_set); + tryAMAGICbin_MG(ne_amg,AMGf_set|AMGf_numeric); #ifndef NV_PRESERVES_UV if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) { SP--; @@ -2247,7 +2247,7 @@ PP(pp_ne) PP(pp_ncmp) { dVAR; dSP; dTARGET; - tryAMAGICbin_MG(ncmp_amg, 0); + tryAMAGICbin_MG(ncmp_amg, AMGf_numeric); #ifndef NV_PRESERVES_UV if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) { const UV right = PTR2UV(SvRV(POPs)); @@ -2571,7 +2571,7 @@ PP(pp_not) PP(pp_complement) { dVAR; dSP; dTARGET; - tryAMAGICun_MG(compl_amg, 0); + tryAMAGICun_MG(compl_amg, AMGf_numeric); { dTOPss; if (SvNIOKp(sv)) { @@ -334,7 +334,7 @@ PP(pp_readline) PP(pp_eq) { dVAR; dSP; - tryAMAGICbin_MG(eq_amg, AMGf_set); + tryAMAGICbin_MG(eq_amg, AMGf_set|AMGf_numeric); #ifndef NV_PRESERVES_UV if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) { SP--; |