From: Rick Delaney Date: Sun, 7 Oct 2007 00:22:14 +0000 (-0400) Subject: Re: [perl #46011] overload "0+" doesn't handle integer results X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c781a409e12d3d0d5a289d2e43b9c4e399d30667;p=p5sagit%2Fp5-mst-13.2.git Re: [perl #46011] overload "0+" doesn't handle integer results Message-ID: <20071007042214.GH29047@bort.ca> p4raw-id: //depot/perl@32059 --- diff --git a/lib/overload.t b/lib/overload.t index 34b4521..9b17923 100644 --- a/lib/overload.t +++ b/lib/overload.t @@ -47,7 +47,7 @@ sub numify { 0 + "${$_[0]}" } # Not needed, additional overhead package main; $| = 1; -use Test::More tests => 528; +use Test::More tests => 535; $a = new Oscalar "087"; @@ -1375,3 +1375,28 @@ foreach my $op (qw(<=> == != < <= > >=)) { is("$wham_eth", $string); is ($crunch_eth->Pie("Blackbird"), "$string, Blackbird"); } + +{ + package numify_int; + use overload "0+" => sub { $_[0][0] += 1; 42 }; + package numify_self; + use overload "0+" => sub { $_[0][0]++; $_[0] }; + package numify_other; + use overload "0+" => sub { $_[0][0]++; $_[0][1] = bless [], 'numify_int' }; + + package main; + my $o = bless [], 'numify_int'; + is(int($o), 42, 'numifies to integer'); + is($o->[0], 1, 'int() numifies only once'); + + my $aref = []; + my $num_val = 0 + $aref; + my $r = bless $aref, 'numify_self'; + is(int($r), $num_val, 'numifies to self'); + is($r->[0], 1, 'int() numifies once when returning self'); + + my $s = bless [], 'numify_other'; + is(int($s), 42, 'numifies to numification of other object'); + is($s->[0], 1, 'int() numifies once when returning other object'); + is($s->[1][0], 1, 'returned object numifies too'); +} diff --git a/pp.c b/pp.c index d55c4a8..c916bf6 100644 --- a/pp.c +++ b/pp.c @@ -2874,22 +2874,38 @@ PP(pp_int) { dVAR; dSP; dTARGET; tryAMAGICun(int); { - const IV iv = TOPi; /* attempt to convert to IV if possible. */ + SV *sv = TOPs; + IV iv; /* XXX it's arguable that compiler casting to IV might be subtly different from modf (for numbers inside (IV_MIN,UV_MAX)) in which else preferring IV has introduced a subtle behaviour change bug. OTOH relying on floating point to be accurate is a bug. */ - if (!SvOK(TOPs)) + while (SvAMAGIC(sv)) { + SV *tsv = AMG_CALLun(sv,numer); + if (SvROK(tsv) && SvRV(tsv) == SvRV(sv)) { + SETi(PTR2IV(SvRV(sv))); + RETURN; + } + else + sv = tsv; + } + iv = SvIV(sv); /* attempt to convert to IV if possible. */ + + if (!SvOK(sv)) { SETu(0); - else if (SvIOK(TOPs)) { - if (SvIsUV(TOPs)) { - const UV uv = TOPu; - SETu(uv); - } else + } + else if (SvIOK(sv)) { + if (SvIsUV(sv)) + SETu(SvUV(sv)); + else SETi(iv); - } else { - const NV value = TOPn; + } + else if (SvROK(sv)) { + SETi(iv); + } + else { + const NV value = SvNV(sv); if (value >= 0.0) { if (value < (NV)UV_MAX + 0.5) { SETu(U_V(value));