diff --git a/MANIFEST b/MANIFEST
index e15db8ea8a32..c6a63b27ed0d 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -5631,6 +5631,7 @@ t/lib/Devel/nodb.pm Module for t/run/switchd.t
t/lib/Devel/switchd.pm Module for t/run/switchd.t
t/lib/Devel/switchd_empty.pm Module for t/run/switchd.t
t/lib/Devel/switchd_goto.pm Module for t/run/switchd.t
+t/lib/feature/autovivification Tests for the autovivification feature
t/lib/feature/bareword_filehandles Tests for enabling/disabling bareword_filehandles feature
t/lib/feature/bits Tests for feature bit handling
t/lib/feature/bundle Tests for feature bundles
diff --git a/cop.h b/cop.h
index 33463a0ab27a..7d9ef2e4737f 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..540d8ff12b1b 100644
--- a/feature.h
+++ b/feature.h
@@ -12,24 +12,25 @@
#define HINT_FEATURE_SHIFT 26
-#define FEATURE_BAREWORD_FILEHANDLES_BIT 0x0001
-#define FEATURE_BITWISE_BIT 0x0002
-#define FEATURE___SUB___BIT 0x0004
-#define FEATURE_MYREF_BIT 0x0008
-#define FEATURE_EVALBYTES_BIT 0x0010
-#define FEATURE_FC_BIT 0x0020
-#define FEATURE_INDIRECT_BIT 0x0040
-#define FEATURE_ISA_BIT 0x0080
-#define FEATURE_MULTIDIMENSIONAL_BIT 0x0100
-#define FEATURE_POSTDEREF_QQ_BIT 0x0200
-#define FEATURE_REFALIASING_BIT 0x0400
-#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_AUTOVIVIFICATION_BIT 0x0001
+#define FEATURE_BAREWORD_FILEHANDLES_BIT 0x0002
+#define FEATURE_BITWISE_BIT 0x0004
+#define FEATURE___SUB___BIT 0x0008
+#define FEATURE_MYREF_BIT 0x0010
+#define FEATURE_EVALBYTES_BIT 0x0020
+#define FEATURE_FC_BIT 0x0040
+#define FEATURE_INDIRECT_BIT 0x0080
+#define FEATURE_ISA_BIT 0x0100
+#define FEATURE_MULTIDIMENSIONAL_BIT 0x0200
+#define FEATURE_POSTDEREF_QQ_BIT 0x0400
+#define FEATURE_REFALIASING_BIT 0x0800
+#define FEATURE_SAY_BIT 0x1000
+#define FEATURE_SIGNATURES_BIT 0x2000
+#define FEATURE_STATE_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
@@ -167,6 +168,13 @@
FEATURE_IS_ENABLED_MASK(FEATURE_UNICODE_BIT)) \
)
+#define FEATURE_AUTOVIVIFICATION_IS_ENABLED \
+ ( \
+ CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_527 \
+ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \
+ FEATURE_IS_ENABLED_MASK(FEATURE_AUTOVIVIFICATION_BIT)) \
+ )
+
#define FEATURE_MULTIDIMENSIONAL_IS_ENABLED \
( \
CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_527 \
@@ -250,6 +258,14 @@ S_magic_sethint_feature(pTHX_ SV *keysv, const char *keypv, STRLEN keylen,
}
return;
+ case 'a':
+ if (keylen == sizeof("feature_autovivification")-1
+ && memcmp(subf+1, "utovivification", keylen - sizeof("feature_")) == 0) {
+ mask = FEATURE_AUTOVIVIFICATION_BIT;
+ break;
+ }
+ return;
+
case 'b':
if (keylen == sizeof("feature_bareword_filehandles")-1
&& memcmp(subf+1, "areword_filehandles", keylen - sizeof("feature_")) == 0) {
diff --git a/lib/feature.pm b/lib/feature.pm
index 9c4179364af0..3e0d9dca7a90 100644
--- a/lib/feature.pm
+++ b/lib/feature.pm
@@ -24,18 +24,19 @@ our %feature = (
unicode_eval => 'feature_unieval',
declared_refs => 'feature_myref',
unicode_strings => 'feature_unicode',
+ autovivification => 'feature_autovivification',
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(autovivification bareword_filehandles indirect multidimensional say state switch)],
+ "5.11" => [qw(autovivification bareword_filehandles indirect multidimensional say state switch unicode_strings)],
+ "5.15" => [qw(autovivification bareword_filehandles current_sub evalbytes fc indirect multidimensional say state switch unicode_eval unicode_strings)],
+ "5.23" => [qw(autovivification bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings)],
+ "5.27" => [qw(autovivification bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings)],
+ "all" => [qw(autovivification 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(autovivification bareword_filehandles indirect multidimensional)],
);
$feature_bundle{"5.12"} = $feature_bundle{"5.11"};
@@ -431,6 +432,14 @@ C are caught by executing the body of the C block.
For more information, see L.
+=head2 The 'autovivification' feature.
+
+This feature enables autovivification of references. It is enabled by
+default, but can be turned off to disable it.
+
+This feature is available under this name from Perl 5.34 onwards, in
+previous versions it was simple on all the time.
+
=head1 FEATURE BUNDLES
It's possible to load multiple features together, using
@@ -444,64 +453,68 @@ The following feature bundles are available:
bundle features included
--------- -----------------
:default indirect multidimensional
- bareword_filehandles
+ bareword_filehandles autovivification
+
+ :5.10 autovivification bareword_filehandles
+ indirect multidimensional say state switch
+
+ :5.12 autovivification bareword_filehandles
+ indirect multidimensional say state switch
+ unicode_strings
+
+ :5.14 autovivification bareword_filehandles
+ indirect multidimensional say state switch
+ unicode_strings
- :5.10 bareword_filehandles indirect
+ :5.16 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
multidimensional say state switch
+ unicode_eval unicode_strings
- :5.12 bareword_filehandles indirect
+ :5.18 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
multidimensional say state switch
- unicode_strings
+ unicode_eval unicode_strings
- :5.14 bareword_filehandles indirect
+ :5.20 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
multidimensional say state switch
- unicode_strings
+ unicode_eval unicode_strings
- :5.16 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional say state
- switch unicode_eval unicode_strings
+ :5.22 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
+ multidimensional say state switch
+ unicode_eval unicode_strings
- :5.18 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional say state
+ :5.24 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
switch unicode_eval unicode_strings
- :5.20 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional say state
+ :5.26 autovivification bareword_filehandles
+ current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
switch unicode_eval unicode_strings
- :5.22 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional say state
+ :5.28 autovivification bareword_filehandles
+ bitwise current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
switch unicode_eval unicode_strings
- :5.24 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional postderef_qq
- say state switch unicode_eval
- unicode_strings
-
- :5.26 bareword_filehandles current_sub evalbytes
- fc indirect multidimensional postderef_qq
- say state 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
-
- :5.30 bareword_filehandles bitwise current_sub
- evalbytes fc indirect multidimensional
- postderef_qq say state switch unicode_eval
- unicode_strings
+ :5.30 autovivification bareword_filehandles
+ bitwise current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
+ 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
+ :5.32 autovivification bareword_filehandles
+ bitwise current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
+ 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
+ :5.34 autovivification bareword_filehandles
+ bitwise current_sub evalbytes fc indirect
+ multidimensional postderef_qq say state
+ 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 c17d1b07d2a7..898a1c6fbfe5 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/pp_hot.c b/pp_hot.c
index c693b301bb54..a7caa65d18e6 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -35,6 +35,7 @@
#define PERL_IN_PP_HOT_C
#include "perl.h"
#include "regcomp.h"
+#include "feature.h"
/* Hot code. */
@@ -5433,6 +5434,21 @@ Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
if (!SvOK(sv)) {
if (SvREADONLY(sv))
Perl_croak_no_modify();
+ if (!FEATURE_AUTOVIVIFICATION_IS_ENABLED) {
+ const char *type = "an unknown";
+ switch (to_what) {
+ case OPpDEREF_SV:
+ type = "a scalar";
+ break;
+ case OPpDEREF_AV:
+ type = "an array";
+ break;
+ case OPpDEREF_HV:
+ type = "a hash";
+ break;
+ }
+ Perl_croak(aTHX_ "Attempt to autovivify %s reference with autovivification disabled", type);
+ }
prepare_SV_for_RV(sv);
switch (to_what) {
case OPpDEREF_SV:
diff --git a/regen/feature.pl b/regen/feature.pl
index e4f8386a0273..e7fe7b1a6e74 100755
--- a/regen/feature.pl
+++ b/regen/feature.pl
@@ -41,6 +41,7 @@ BEGIN
multidimensional => 'multidimensional',
bareword_filehandles => 'bareword_filehandles',
try => 'try',
+ autovivification => 'autovivification',
);
# 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 autovivification};
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 autovivification} ],
# using 5.9.5 features bundle
"5.9.5" => [ +V5_9_5 ],
"5.10" => [ +V5_9_5 ],
@@ -836,6 +838,14 @@ =head2 The 'try' feature.
For more information, see L.
+=head2 The 'autovivification' feature.
+
+This feature enables autovivification of references. It is enabled by
+default, but can be turned off to disable it.
+
+This feature is available under this name from Perl 5.34 onwards, in
+previous versions it was simple on all the time.
+
=head1 FEATURE BUNDLES
It's possible to load multiple features together, using
diff --git a/t/lib/feature/autovivification b/t/lib/feature/autovivification
new file mode 100644
index 000000000000..f36f5d6cd986
--- /dev/null
+++ b/t/lib/feature/autovivification
@@ -0,0 +1,50 @@
+Test the autovivification feature
+
+__END__
+# NAME hash autovivification
+use feature 'say'; # ensure the autoviv test depends on cop_warnings, not cop_hints
+my $x;
+$x->{foo} = 1;
+no feature 'autovivification';
+undef $x;
+$x->{foo} = 1;
+EXPECT
+Attempt to autovivify a hash reference with autovivification disabled at - line 6.
+########
+# NAME hash autovivification (subhash)
+use feature 'say'; # ensure the autoviv test depends on cop_warnings, not cop_hints
+my $x = {};
+$x->{foo} = 1;
+$x->{foo}{bar} = 1;
+no feature 'autovivification';
+$x = {};
+$x->{foo}{bar} = 1;
+EXPECT
+Attempt to autovivify a hash reference with autovivification disabled at - line 7.
+########
+# NAME array autovivification
+my $x;
+$x->[0] = 1;
+undef $x;
+no feature 'autovivification';
+$x->[0] = 2;
+EXPECT
+Attempt to autovivify an array reference with autovivification disabled at - line 5.
+########
+# NAME array autovivification (sub array)
+my $x = {};
+$x->{foo}[0] = 1;
+$x = {};
+no feature 'autovivification';
+$x->{foo}[0] = 2;
+EXPECT
+Attempt to autovivify an array reference with autovivification disabled at - line 5.
+########
+# NAME scalar autovivification
+my $x;
+$$x = 1;
+undef $x;
+no feature 'autovivification';
+$$x = 2;
+EXPECT
+Attempt to autovivify a scalar reference with autovivification disabled at - line 5.