diff --git a/MANIFEST b/MANIFEST index df0e398a10c6..6f0d0d4afa8a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -5639,6 +5639,7 @@ t/lib/feature/multidimensional Tests for enabling/disabling $foo{$x, $y} => $foo t/lib/feature/nonesuch Tests for enabling/disabling nonexistent feature t/lib/feature/removed Tests for enabling/disabling removed feature t/lib/feature/say Tests for enabling/disabling say feature +t/lib/feature/stringification Tests for enabling/disabling stringification feature t/lib/feature/switch Tests for enabling/disabling switch feature t/lib/h2ph.h Test header file for h2ph t/lib/h2ph.pht Generated output from h2ph.h by h2ph, for comparison diff --git a/cop.h b/cop.h index b5f30bd0415f..777fb3bf7f5b 100644 --- a/cop.h +++ b/cop.h @@ -576,6 +576,8 @@ string C

, creating the package if necessary. #define CopHINTHASH_get(c) ((COPHH*)((c)->cop_hints_hash)) #define CopHINTHASH_set(c,h) ((c)->cop_hints_hash = (h)) +#define CopFEATURES_setfrom(c, o) ((c)->cop_features = (o)->cop_features) + /* =for apidoc Am|SV *|cop_hints_fetch_pvn|const COP *cop|const char *keypv|STRLEN keylen|U32 hash|U32 flags diff --git a/feature.h b/feature.h index 501bc3a3b180..e7a0c0f97747 100644 --- a/feature.h +++ b/feature.h @@ -26,10 +26,11 @@ #define FEATURE_SAY_BIT 0x0800 #define FEATURE_SIGNATURES_BIT 0x1000 #define FEATURE_STATE_BIT 0x2000 -#define FEATURE_SWITCH_BIT 0x4000 -#define FEATURE_TRY_BIT 0x8000 -#define FEATURE_UNIEVAL_BIT 0x10000 -#define FEATURE_UNICODE_BIT 0x20000 +#define FEATURE_STRINGIFICATION_BIT 0x4000 +#define FEATURE_SWITCH_BIT 0x8000 +#define FEATURE_TRY_BIT 0x10000 +#define FEATURE_UNIEVAL_BIT 0x20000 +#define FEATURE_UNICODE_BIT 0x40000 #define FEATURE_BUNDLE_DEFAULT 0 #define FEATURE_BUNDLE_510 1 @@ -159,6 +160,13 @@ FEATURE_IS_ENABLED_MASK(FEATURE_MYREF_BIT) \ ) +#define FEATURE_STRINGIFICATION_IS_ENABLED \ + ( \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_527 \ + || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ + FEATURE_IS_ENABLED_MASK(FEATURE_STRINGIFICATION_BIT)) \ + ) + #define FEATURE_UNICODE_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_511 && \ @@ -337,6 +345,11 @@ S_magic_sethint_feature(pTHX_ SV *keysv, const char *keypv, STRLEN keylen, mask = FEATURE_STATE_BIT; break; } + else if (keylen == sizeof("feature_stringification")-1 + && memcmp(subf+1, "tringification", keylen - sizeof("feature_")) == 0) { + mask = FEATURE_STRINGIFICATION_BIT; + break; + } else if (keylen == sizeof("feature_switch")-1 && memcmp(subf+1, "witch", keylen - sizeof("feature_")) == 0) { mask = FEATURE_SWITCH_BIT; diff --git a/lib/feature.pm b/lib/feature.pm index a1953e292e54..8507644cc40e 100644 --- a/lib/feature.pm +++ b/lib/feature.pm @@ -23,19 +23,20 @@ our %feature = ( postderef_qq => 'feature_postderef_qq', unicode_eval => 'feature_unieval', declared_refs => 'feature_myref', + stringification => 'feature_stringification', unicode_strings => 'feature_unicode', multidimensional => 'feature_multidimensional', bareword_filehandles => 'feature_bareword_filehandles', ); our %feature_bundle = ( - "5.10" => [qw(bareword_filehandles indirect multidimensional say state switch)], - "5.11" => [qw(bareword_filehandles indirect multidimensional say state switch unicode_strings)], - "5.15" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional say state switch unicode_eval unicode_strings)], - "5.23" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings)], - "5.27" => [qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings)], - "all" => [qw(bareword_filehandles bitwise current_sub declared_refs evalbytes fc indirect isa multidimensional postderef_qq refaliasing say signatures state switch try unicode_eval unicode_strings)], - "default" => [qw(bareword_filehandles indirect multidimensional)], + "5.10" => [qw(bareword_filehandles indirect multidimensional say state stringification switch)], + "5.11" => [qw(bareword_filehandles indirect multidimensional say state stringification switch unicode_strings)], + "5.15" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional say state stringification switch unicode_eval unicode_strings)], + "5.23" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state stringification switch unicode_eval unicode_strings)], + "5.27" => [qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state stringification switch unicode_eval unicode_strings)], + "all" => [qw(bareword_filehandles bitwise current_sub declared_refs evalbytes fc indirect isa multidimensional postderef_qq refaliasing say signatures state stringification switch try unicode_eval unicode_strings)], + "default" => [qw(bareword_filehandles indirect multidimensional stringification)], ); $feature_bundle{"5.12"} = $feature_bundle{"5.11"}; @@ -431,6 +432,17 @@ C are caught by executing the body of the C block. For more information, see L. +=head2 The 'stringification' feature + +This feature enables converting references that have no string +overloading into strings as described in L. It is enabled by +default, but can be turned off to disable such conversions. + +Disabling this feature does not prevent numeric conversions. + +This feature is enabled under this name from Perl 5.34 onwards. In +previous versions it was simply on all the time. + =head1 FEATURE BUNDLES It's possible to load multiple features together, using @@ -444,64 +456,69 @@ The following feature bundles are available: bundle features included --------- ----------------- :default indirect multidimensional - bareword_filehandles + bareword_filehandles stringification :5.10 bareword_filehandles indirect - multidimensional say state switch + multidimensional say state stringification + switch :5.12 bareword_filehandles indirect - multidimensional say state switch - unicode_strings + multidimensional say state stringification + switch unicode_strings :5.14 bareword_filehandles indirect - multidimensional say state switch - unicode_strings + multidimensional say state stringification + switch unicode_strings :5.16 bareword_filehandles current_sub evalbytes fc indirect multidimensional say state - switch unicode_eval unicode_strings + stringification switch unicode_eval + unicode_strings :5.18 bareword_filehandles current_sub evalbytes fc indirect multidimensional say state - switch unicode_eval unicode_strings + stringification switch unicode_eval + unicode_strings :5.20 bareword_filehandles current_sub evalbytes fc indirect multidimensional say state - switch unicode_eval unicode_strings + stringification switch unicode_eval + unicode_strings :5.22 bareword_filehandles current_sub evalbytes fc indirect multidimensional say state - switch unicode_eval unicode_strings + stringification switch unicode_eval + unicode_strings :5.24 bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq - say state switch unicode_eval - unicode_strings + say state stringification switch + unicode_eval unicode_strings :5.26 bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq - say state switch unicode_eval - unicode_strings + say state stringification switch + unicode_eval unicode_strings :5.28 bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional - postderef_qq say state switch unicode_eval - unicode_strings + postderef_qq say state stringification + switch unicode_eval unicode_strings :5.30 bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional - postderef_qq say state switch unicode_eval - unicode_strings + postderef_qq say state stringification + switch unicode_eval unicode_strings :5.32 bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional - postderef_qq say state switch unicode_eval - unicode_strings + postderef_qq say state stringification + switch unicode_eval unicode_strings :5.34 bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional - postderef_qq say state switch unicode_eval - unicode_strings + postderef_qq say state stringification + switch unicode_eval unicode_strings :5.36 bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional diff --git a/op.c b/op.c index 61f7eaad7513..8279896cd494 100644 --- a/op.c +++ b/op.c @@ -9425,6 +9425,7 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o) cop->cop_seq = seq; cop->cop_warnings = DUP_WARNINGS(PL_curcop->cop_warnings); CopHINTHASH_set(cop, cophh_copy(CopHINTHASH_get(PL_curcop))); + CopFEATURES_setfrom(cop, PL_curcop); if (label) { Perl_cop_store_label(aTHX_ cop, label, strlen(label), utf8); diff --git a/pod/perldiag.pod b/pod/perldiag.pod index 88df9485059e..a0e74f3fbcbf 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -413,6 +413,11 @@ assigning through that reference. For example $r = do {my @a; \$#a}; $$r = 503 +=item Attempt to stringify reference under no feature stringification + +(F) You tried to use a reference that has no string overloading in +string context in lexical context of C + =item Attempt to use reference as lvalue in substr (W substr) You supplied a reference as the first argument to substr() diff --git a/regen/feature.pl b/regen/feature.pl index 19af0a35ce41..36ab4b69f30d 100755 --- a/regen/feature.pl +++ b/regen/feature.pl @@ -41,6 +41,7 @@ BEGIN multidimensional => 'multidimensional', bareword_filehandles => 'bareword_filehandles', try => 'try', + stringification => 'stringification', ); # NOTE: If a feature is ever enabled in a non-contiguous range of Perl @@ -50,7 +51,8 @@ BEGIN # 5.odd implies the next 5.even, but an explicit 5.even can override it. # features bundles -use constant V5_9_5 => sort qw{say state switch indirect multidimensional bareword_filehandles}; +use constant V5_9_5 => sort qw{say state switch indirect multidimensional bareword_filehandles + stringification}; use constant V5_11 => sort ( +V5_9_5, qw{unicode_strings} ); use constant V5_15 => sort ( +V5_11, qw{unicode_eval evalbytes current_sub fc} ); use constant V5_23 => sort ( +V5_15, qw{postderef_qq} ); @@ -58,7 +60,7 @@ BEGIN my %feature_bundle = ( all => [ sort keys %feature ], - default => [ qw{indirect multidimensional bareword_filehandles} ], + default => [ qw{indirect multidimensional bareword_filehandles stringification} ], # using 5.9.5 features bundle "5.9.5" => [ +V5_9_5 ], "5.10" => [ +V5_9_5 ], @@ -836,6 +838,17 @@ =head2 The 'try' feature. For more information, see L. +=head2 The 'stringification' feature + +This feature enables converting references that have no string +overloading into strings as described in L. It is enabled by +default, but can be turned off to disable such conversions. + +Disabling this feature does not prevent numeric conversions. + +This feature is enabled under this name from Perl 5.34 onwards. In +previous versions it was simply on all the time. + =head1 FEATURE BUNDLES It's possible to load multiple features together, using diff --git a/sv.c b/sv.c index eec33eb5cab1..a9d25070c6f4 100644 --- a/sv.c +++ b/sv.c @@ -31,6 +31,7 @@ #define PERL_IN_SV_C #include "perl.h" #include "regcomp.h" +#include "feature.h" #ifdef __VMS # include #endif @@ -3105,6 +3106,11 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const U32 flags) if (lp) *lp = len; SAVEFREEPV(buffer); + + if (!FEATURE_STRINGIFICATION_IS_ENABLED) { + Perl_croak(aTHX_ "Attempt to stringify reference under no feature stringification"); + } + return retval; } } diff --git a/t/lib/feature/stringification b/t/lib/feature/stringification new file mode 100644 index 000000000000..320a595dd2f9 --- /dev/null +++ b/t/lib/feature/stringification @@ -0,0 +1,29 @@ +Test no feature stringification + +__END__ +# NAME simple +# default on +my $x = \1; +my $y = "$x"; +# on in bundles +use v5.10.0; +$y = "$x"; +use v5.32.0; +$y = "$x"; +use feature ":5.32.0"; # feature and use v end up different under the hood. +$y = "$x"; +no feature "stringification"; +$y = "$x"; +EXPECT +OPTIONS fatal +Attempt to stringify reference under no feature stringification at - line 12. +######## +# NAME overloaded +package Foo { + use overload '""' => sub { "ABC" }; +}; +my $x = bless {}, "Foo"; +no feature "stringification"; +print $x, "\n"; +EXPECT +ABC