Commit 97df6ed824 for perl
commit 97df6ed824bf359753a008572dbe3112368ed371
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date: Sat Nov 7 22:00:52 2026 +0000
PL_sv_zero - remove SVf_POK to make it seem number-first
`PL_sv_zero`, introduced in 5.28, has a zero numeric value and a "0"
string value. Its flags did not indicate which value should be treated
as authoritative when serializing or encoding to an external format.
This could lead to what was originally a numerical return value being
output as the string representation instead, which might not have the
same meaning (e.g. in JSON).
The flags on `PL_sv_zero` have been modified so that it appears to
have been created as a number and later gained a string representation.
This is intended as an aid to serializers that differentiate between
"created as number" and "created as string".
diff --git a/lib/builtin.t b/lib/builtin.t
index e01ddb45ca..0d245d57c3 100644
--- a/lib/builtin.t
+++ b/lib/builtin.t
@@ -752,6 +752,17 @@ EOS
is($h{123}, 456, "Numerical OP_CONST SVs in hash init are created_as_number() when hekified");
}
+# array element counts are numbers, even if that number is zero
+{
+ use builtin qw( created_as_number created_as_string);
+ my @arr;
+ ok(created_as_number(scalar @arr), 'scalar @arr on empty array created_as_number');
+ ok(!created_as_string(scalar @arr), 'scalar @arr on empty array not created_as_string');
+ push @arr, "abcde";
+ ok(created_as_number(scalar @arr), 'scalar @arr on single element array created_as_number');
+ ok(!created_as_string(scalar @arr), 'scalar @arr on single element array not created_as_string');
+}
+
# vim: tabstop=4 shiftwidth=4 expandtab autoindent softtabstop=4
done_testing();
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 5bca15ac88..4002c085cf 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -528,6 +528,21 @@ refaliasing and the C<builtin::indexed> function. [GH #24999]
say "Array number [$idx] contains <@arr>";
}
+=item *
+
+C<PL_sv_zero>, introduced in 5.28, has a zero numeric value and a "0"
+string value. Its flags did not indicate which value should be treated
+as authoritative when serializing or encoding to an external format.
+This could lead to what was originally a numerical return value being
+output as the string representation instead, which might not have the
+same meaning (e.g. in JSON).
+
+The flags on C<PL_sv_zero> have been modified so that it appears to have
+been created as a number and then later gained a string representation.
+This change is intended to make it easier for serialization modules to
+output C<0> rather than C<"0">, provided that such modules actually do
+differentiate between "created as number" and "created as string".
+
=back
=head1 Known Problems
diff --git a/sv.c b/sv.c
index 8a508a3f7d..3630de0ee6 100644
--- a/sv.c
+++ b/sv.c
@@ -18170,7 +18170,7 @@ Perl_init_constants(pTHX)
SvREFCNT(&PL_sv_zero) = SvREFCNT_IMMORTAL;
SvFLAGS(&PL_sv_zero) = SVt_PVNV|SVf_READONLY|SVf_PROTECT
|SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
- |SVp_POK|SVf_POK
+ |SVp_POK
|SVs_PADTMP;
SvPV_set(&PL_sv_no, (char*)PL_No);
diff --git a/t/op/svflags.t b/t/op/svflags.t
index 0c7f27b46d..703ea6d26b 100644
--- a/t/op/svflags.t
+++ b/t/op/svflags.t
@@ -10,7 +10,7 @@ BEGIN {
# Tests the new documented mechanism for determining the original type
# of an SV.
-plan tests => 23;
+plan tests => 24;
use strict;
use B qw(svref_2object SVf_IOK SVf_NOK SVf_POK);
@@ -122,3 +122,9 @@ s'foo'bar'
CODE
unlike($got, qr/Conditional jump or move depends on uninitialised value/,
'All fields initialized in SVt_PV[IV|NV|MG] copies');
+
+my @arr;
+# pp_padav pushes $PL_sv_zero to the stack here
+my $sc = scalar @arr;
+$xobj = svref_2object(\$sc);
+is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero behaves as number (not string) first");