From 84b31b4e450264de173bfb4c8e520667307cc25a Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 8 Oct 2024 15:00:12 +1100 Subject: [PATCH 1/9] Revert "parent: don't test ' in names from 5.41." This reverts commit 83d4e742eb83e1e6c50fb82e3c7ac1a366337909. This also bumps the version number. --- cpan/parent/lib/parent.pm | 2 +- cpan/parent/t/compile-time-file.t | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cpan/parent/lib/parent.pm b/cpan/parent/lib/parent.pm index 89c9ff84cf74..09d89cffac11 100644 --- a/cpan/parent/lib/parent.pm +++ b/cpan/parent/lib/parent.pm @@ -1,7 +1,7 @@ package parent; use strict; -our $VERSION = '0.242'; +our $VERSION = '0.242_001'; sub import { my $class = shift; diff --git a/cpan/parent/t/compile-time-file.t b/cpan/parent/t/compile-time-file.t index 0fcf8d8a2a65..bff886155297 100644 --- a/cpan/parent/t/compile-time-file.t +++ b/cpan/parent/t/compile-time-file.t @@ -24,7 +24,7 @@ use lib 't/lib'; { package Child3; - use if $] < 5.041_003, parent => "Dummy'Outside"; + use parent "Dummy'Outside"; } my $obj = {}; @@ -39,13 +39,9 @@ isa_ok $obj, 'Dummy::InlineChild'; can_ok $obj, 'exclaim'; is $obj->exclaim, "I CAN FROM Dummy::InlineChild", 'Inheritance is set up correctly for inlined classes'; -SKIP: -{ - skip "No ' in names from 5.041_003", 3 if $] >= 5.041_003; $obj = {}; bless $obj, 'Child3'; isa_ok $obj, 'Dummy::Outside'; can_ok $obj, 'exclaim'; is $obj->exclaim, "I CAN FROM Dummy::Outside", "Inheritance is set up correctly for classes inherited from via '"; -} From 4a75361c2559de0e48200292019f1654433457db Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 8 Oct 2024 15:05:32 +1100 Subject: [PATCH 2/9] Revert "Scalar::List::Utils: ' not special in names from v5.41" This reverts commit 87e1ec10b4ba12f40e63b7c3cc33bbbb89d40781 with some adjustments due to upstream changes. --- cpan/Scalar-List-Utils/ListUtil.xs | 8 -------- cpan/Scalar-List-Utils/lib/List/Util.pm | 2 +- cpan/Scalar-List-Utils/lib/List/Util/XS.pm | 2 +- cpan/Scalar-List-Utils/lib/Scalar/Util.pm | 2 +- cpan/Scalar-List-Utils/lib/Sub/Util.pm | 2 +- cpan/Scalar-List-Utils/t/exotic_names.t | 4 ++-- 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/cpan/Scalar-List-Utils/ListUtil.xs b/cpan/Scalar-List-Utils/ListUtil.xs index f67e9d4e1af2..855d8abdcaf2 100644 --- a/cpan/Scalar-List-Utils/ListUtil.xs +++ b/cpan/Scalar-List-Utils/ListUtil.xs @@ -1951,10 +1951,8 @@ PREINIT: STRLEN namelen; const char* nameptr = SvPV(name, namelen); int utf8flag = SvUTF8(name); -#if PERL_VERSION_LT(5, 41, 3) int quotes_seen = 0; bool need_subst = FALSE; -#endif PPCODE: if (!SvROK(sub) && SvGMAGICAL(sub)) mg_get(sub); @@ -1977,23 +1975,18 @@ PPCODE: if (s > nameptr && *s == ':' && s[-1] == ':') { end = s - 1; begin = ++s; -#if PERL_VERSION_LT(5, 41, 3) if (quotes_seen) need_subst = TRUE; -#endif } -#if PERL_VERSION_LT(5, 41, 3) else if (s > nameptr && *s != '\0' && s[-1] == '\'') { end = s - 1; begin = s; if (quotes_seen++) need_subst = TRUE; } -#endif } s--; if (end) { -#if PERL_VERSION_LT(5, 41, 3) SV* tmp; if (need_subst) { STRLEN length = end - nameptr + quotes_seen - (*end == '\'' ? 1 : 0); @@ -2013,7 +2006,6 @@ PPCODE: stash = gv_stashpvn(left, length, GV_ADD | utf8flag); } else -#endif stash = gv_stashpvn(nameptr, end - nameptr, GV_ADD | utf8flag); nameptr = begin; namelen -= begin - nameptr; diff --git a/cpan/Scalar-List-Utils/lib/List/Util.pm b/cpan/Scalar-List-Utils/lib/List/Util.pm index e50aefa63d50..f5ab5c8ff366 100644 --- a/cpan/Scalar-List-Utils/lib/List/Util.pm +++ b/cpan/Scalar-List-Utils/lib/List/Util.pm @@ -16,7 +16,7 @@ our @EXPORT_OK = qw( sample shuffle uniq uniqint uniqnum uniqstr zip zip_longest zip_shortest mesh mesh_longest mesh_shortest head tail pairs unpairs pairkeys pairvalues pairmap pairgrep pairfirst ); -our $VERSION = "1.68"; +our $VERSION = "1.68_01"; our $XS_VERSION = $VERSION; $VERSION =~ tr/_//d; diff --git a/cpan/Scalar-List-Utils/lib/List/Util/XS.pm b/cpan/Scalar-List-Utils/lib/List/Util/XS.pm index bac76f18eb17..801de5cf50de 100644 --- a/cpan/Scalar-List-Utils/lib/List/Util/XS.pm +++ b/cpan/Scalar-List-Utils/lib/List/Util/XS.pm @@ -3,7 +3,7 @@ use strict; use warnings; use List::Util; -our $VERSION = "1.68"; # FIXUP +our $VERSION = "1.68_01"; # FIXUP $VERSION =~ tr/_//d; # FIXUP 1; diff --git a/cpan/Scalar-List-Utils/lib/Scalar/Util.pm b/cpan/Scalar-List-Utils/lib/Scalar/Util.pm index 0ba9af2fddc9..8562a09026d1 100644 --- a/cpan/Scalar-List-Utils/lib/Scalar/Util.pm +++ b/cpan/Scalar-List-Utils/lib/Scalar/Util.pm @@ -17,7 +17,7 @@ our @EXPORT_OK = qw( dualvar isdual isvstring looks_like_number openhandle readonly set_prototype tainted ); -our $VERSION = "1.68"; +our $VERSION = "1.68_01"; $VERSION =~ tr/_//d; require List::Util; # List::Util loads the XS diff --git a/cpan/Scalar-List-Utils/lib/Sub/Util.pm b/cpan/Scalar-List-Utils/lib/Sub/Util.pm index e7a5aaff2de7..4a441163a677 100644 --- a/cpan/Scalar-List-Utils/lib/Sub/Util.pm +++ b/cpan/Scalar-List-Utils/lib/Sub/Util.pm @@ -15,7 +15,7 @@ our @EXPORT_OK = qw( subname set_subname ); -our $VERSION = "1.68"; +our $VERSION = "1.68_01"; $VERSION =~ tr/_//d; require List::Util; # as it has the XS diff --git a/cpan/Scalar-List-Utils/t/exotic_names.t b/cpan/Scalar-List-Utils/t/exotic_names.t index 15d1ff1c9517..e37418d7ed0e 100644 --- a/cpan/Scalar-List-Utils/t/exotic_names.t +++ b/cpan/Scalar-List-Utils/t/exotic_names.t @@ -45,7 +45,7 @@ sub caller3_ok { ), ); - $expected =~ s/'/::/g if $] < 5.041_003; + $expected =~ s/'/::/g; # this is apparently how things worked before 5.16 utf8::encode($expected) if $] < 5.016 and $ord > 255; @@ -85,7 +85,7 @@ my @ordinal = ( my $legal_ident_char = join('', "A-Z_a-z0-9", - ($] < 5.037009 ? q['] : ()), + q['], ($] > 5.008 ? ( map chr, 0x100, 0x498 ) : ()), From 0246bf1e15f728b2f26a84dcedac73b61c36a63a Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 8 Oct 2024 15:06:17 +1100 Subject: [PATCH 3/9] Revert "remove use of ' as a package separator" This reverts commit ce1383eae4cd16b18ff9df6cecb54582e0c689ab. --- embed.fnc | 9 +++- embed.h | 3 +- gv.c | 28 ++++++++-- lib/overload.t | 2 +- mg.c | 2 +- op.c | 11 +++- pod/perldata.pod | 21 +++++--- pod/perldiag.pod | 18 ++++++- pod/perlmod.pod | 18 +++++-- proto.h | 7 ++- t/comp/package.t | 18 ++++--- t/comp/parser.t | 37 +++++++++---- t/lib/croak/toke | 18 +------ t/lib/warnings/toke | 31 ++++++++--- t/op/magic.t | 10 +--- t/op/method.t | 8 ++- t/op/ref.t | 27 +++++++--- t/op/sort.t | 2 +- t/op/stash.t | 6 ++- t/op/stash_parse_gv.t | 4 +- t/uni/package.t | 15 ++++-- t/uni/parser.t | 8 +-- t/uni/stash.t | 6 ++- t/uni/variables.t | 9 +++- toke.c | 119 +++++++++++++++++++++++++++++++----------- 25 files changed, 311 insertions(+), 126 deletions(-) diff --git a/embed.fnc b/embed.fnc index 198073342d2e..8082864919d3 100644 --- a/embed.fnc +++ b/embed.fnc @@ -3018,6 +3018,12 @@ EXpx |char * |scan_word |NN char *s \ |STRLEN destlen \ |int allow_package \ |NN STRLEN *slp +EXpx |char * |scan_word6 |NN char *s \ + |NN char *dest \ + |STRLEN destlen \ + |int allow_package \ + |NN STRLEN *slp \ + |bool warn_tick Cp |U32 |seed : Only used by perl.c/miniperl.c, but defined in caretx.c ep |void |set_caret_X @@ -5903,7 +5909,8 @@ S |void |parse_ident |NN char **s \ |NN char * const e \ |int allow_package \ |bool is_utf8 \ - |bool check_dollar + |bool check_dollar \ + |bool tick_warn S |int |pending_ident RS |char * |scan_const |NN char *start RS |char * |scan_formline |NN char *s diff --git a/embed.h b/embed.h index 973978756dc2..458fa1aba984 100644 --- a/embed.h +++ b/embed.h @@ -1629,7 +1629,7 @@ # define intuit_more(a,b) S_intuit_more(aTHX_ a,b) # define lop(a,b,c) S_lop(aTHX_ a,b,c) # define missingterm(a,b) S_missingterm(aTHX_ a,b) -# define parse_ident(a,b,c,d,e,f) S_parse_ident(aTHX_ a,b,c,d,e,f) +# define parse_ident(a,b,c,d,e,f,g) S_parse_ident(aTHX_ a,b,c,d,e,f,g) # define pending_ident() S_pending_ident(aTHX) # define scan_const(a) S_scan_const(aTHX_ a) # define scan_formline(a) S_scan_formline(aTHX_ a) @@ -1766,6 +1766,7 @@ # define report_uninit(a) Perl_report_uninit(aTHX_ a) # define scan_str(a,b,c,d,e) Perl_scan_str(aTHX_ a,b,c,d,e) # define scan_word(a,b,c,d,e) Perl_scan_word(aTHX_ a,b,c,d,e) +# define scan_word6(a,b,c,d,e,f) Perl_scan_word6(aTHX_ a,b,c,d,e,f) # define skipspace_flags(a,b) Perl_skipspace_flags(aTHX_ a,b) # define sv_magicext_mglob(a) Perl_sv_magicext_mglob(aTHX_ a) # define sv_only_taint_gmagic Perl_sv_only_taint_gmagic diff --git a/gv.c b/gv.c index e0a3ef88ba95..bfd5f30fefae 100644 --- a/gv.c +++ b/gv.c @@ -1179,7 +1179,7 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le * method name. * * leaves last_separator pointing to the beginning of the - * last package separator (::) or 0 + * last package separator (either ' or ::) or 0 * if none was found. * * leaves name pointing at the beginning of the @@ -1188,7 +1188,11 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le const char *name_cursor = name; const char * const name_em1 = name_end - 1; /* name_end minus 1 */ for (name_cursor = name; name_cursor < name_end ; name_cursor++) { - if (name_cursor < name_em1 && *name_cursor == ':' && name_cursor[1] == ':') { + if (*name_cursor == '\'') { + last_separator = name_cursor; + name = name_cursor + 1; + } + else if (name_cursor < name_em1 && *name_cursor == ':' && name_cursor[1] == ':') { last_separator = name_cursor++; name = name_cursor + 1; } @@ -1798,6 +1802,7 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name, const char *name_cursor; const char *const name_end = nambeg + full_len; const char *const name_em1 = name_end - 1; + char smallbuf[64]; /* small buffer to avoid a malloc when possible */ PERL_ARGS_ASSERT_PARSE_GV_STASH_NAME; @@ -1811,7 +1816,8 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name, for (name_cursor = *name; name_cursor < name_end; name_cursor++) { if (name_cursor < name_em1 && - (*name_cursor == ':' && name_cursor[1] == ':')) + ((*name_cursor == ':' && name_cursor[1] == ':') + || *name_cursor == '\'')) { if (!*stash) *stash = PL_defstash; @@ -1826,6 +1832,22 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name, key = *name; *len += 2; } + else { /* using ' for package separator */ + /* use our pre-allocated buffer when possible to save a malloc */ + char *tmpbuf; + if ( *len+2 <= sizeof smallbuf) + tmpbuf = smallbuf; + else { + /* only malloc once if needed */ + if (tmpfullbuf == NULL) /* only malloc&free once, a little more than needed */ + Newx(tmpfullbuf, full_len+2, char); + tmpbuf = tmpfullbuf; + } + Copy(*name, tmpbuf, *len, char); + tmpbuf[(*len)++] = ':'; + tmpbuf[(*len)++] = ':'; + key = tmpbuf; + } gvp = (GV**)hv_fetch(*stash, key, is_utf8 ? -((I32)*len) : (I32)*len, add); *gv = gvp ? *gvp : NULL; if (!*gv || *gv == (const GV *)&PL_sv_undef) { diff --git a/lib/overload.t b/lib/overload.t index afe76d707cf8..11062866b7d3 100644 --- a/lib/overload.t +++ b/lib/overload.t @@ -2395,7 +2395,7 @@ is eval {"$a"}, overload::StrVal($a), { package mane; use overload q\""\ => "bear::strength"; - use overload bool => "bear::bouillon"; + use overload bool => "bear'bouillon"; } @bear::ISA = 'food'; sub food::strength { 'twine' } diff --git a/mg.c b/mg.c index c37707be462d..d972781ff1fe 100644 --- a/mg.c +++ b/mg.c @@ -1853,7 +1853,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg) * access to a known hint bit in a known OP, we can't * tell whether HINT_STRICT_REFS is in force or not. */ - if (!memchr(s, ':', len)) + if (!memchr(s, ':', len) && !memchr(s, '\'', len)) Perl_sv_insert_flags(aTHX_ sv, 0, 0, STR_WITH_LEN("main::"), SV_GMAGIC); if (i) diff --git a/op.c b/op.c index 4ba61a641d2e..4bc9a036644e 100644 --- a/op.c +++ b/op.c @@ -10717,7 +10717,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, ec ? GV_NOADD_NOINIT : (IN_PERL_RUNTIME && PL_curstash != CopSTASH(PL_curcop)) || PL_curstash != PL_defstash - || memchr(name, ':', namlen) + || memchr(name, ':', namlen) || memchr(name, '\'', namlen) ? gv_fetch_flags : GV_ADDMULTI | GV_NOINIT | GV_NOTQUAL; gv = gv_fetchsv(cSVOPo->op_sv, flags, SVt_PVCV); @@ -13380,6 +13380,7 @@ Perl_ck_method(pTHX_ OP *o) { SV *sv, *methsv, *rclass; const char* method; + char* compatptr; int utf8; STRLEN len, nsplit = 0, i; OP* new_op; @@ -13390,6 +13391,14 @@ Perl_ck_method(pTHX_ OP *o) sv = kSVOP->op_sv; + /* replace ' with :: */ + while ((compatptr = (char *) memchr(SvPVX(sv), '\'', + SvEND(sv) - SvPVX(sv) ))) + { + *compatptr = ':'; + sv_insert(sv, compatptr - SvPVX_const(sv), 0, ":", 1); + } + method = SvPVX_const(sv); len = SvCUR(sv); utf8 = SvUTF8(sv) ? -1 : 1; diff --git a/pod/perldata.pod b/pod/perldata.pod index 1a6b842841de..674386bb5625 100644 --- a/pod/perldata.pod +++ b/pod/perldata.pod @@ -136,17 +136,22 @@ generic characters, and identifiers should match That is, any word character in the ASCII range, as long as the first character is not a digit. -There is one package separator in Perl: A double colon (C<::>). -Normal identifiers can start or end with a double colon, and can -contain several parts delimited by double colons. - -Previously you could use C<'> as a package separator, this was removed -in Perl 5.42. +There are two package separators in Perl: A double colon (C<::>) and a single +quote (C<'>). Use of C<'> as the package separator is deprecated and will be +removed in Perl 5.40. Normal identifiers can start or end with a double +colon, and can contain several parts delimited by double colons. Single +quotes have similar rules, but with the exception that they are not legal at +the end of an identifier: That is, C<$'foo> and C<$foo'bar> are legal, but +C<$foo'bar'> is not. Additionally, if the identifier is preceded by a sigil -- that is, if the identifier is part of a variable name -- it may optionally be enclosed in braces. +While you can mix double colons with singles quotes, the quotes must come +after the colons: C<$::::'foo> and C<$foo::'bar> are legal, but C<$::'::foo> +and C<$foo'::bar> are not. + Put together, a grammar to match a basic identifier becomes / @@ -159,9 +164,9 @@ Put together, a grammar to match a basic identifier becomes ) ) (? - (?: :: )* + (?: :: )* '? (?&basic_identifier) - (?: (?= :: ) (?&normal_identifier) )? + (?: (?= (?: :: )+ '? | (?: :: )* ' ) (?&normal_identifier) )? (?: :: )* ) (? diff --git a/pod/perldiag.pod b/pod/perldiag.pod index 1af0dcc364b1..ebbe174eb460 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -487,7 +487,7 @@ results. of Perl. Check the #! line, or manually feed your script into Perl yourself. -=item Bad name after %s:: +=item Bad name after %s (F) You started to name a symbol by using a package prefix, and then didn't finish the symbol. In particular, you can't interpolate outside @@ -4759,6 +4759,22 @@ Cing a file, or when seeking past the end of a scalar opened for I/O (in anticipation of future reads and to imitate the behavior with real files). +=item Old package separator "'" deprecated + +(D deprecated::apostrophe_as_package_separator, syntax) You used the old package +separator "'" in a variable, subroutine or package name. Support for the +old package separator will be removed in Perl 5.42. + +=item Old package separator used in string + +(D deprecated::apostrophe_as_package_separator, syntax) You used the old package +separator, "'", in a variable named inside a double-quoted string; e.g., +C<"In $name's house">. This is equivalent to C<"In $name::s house">. If +you meant the former, put a backslash before the apostrophe +(C<"In $name\'s house">). + +Support for the old package separator will be removed in Perl 5.42. + =item Only scalar fields can take a :param attribute (F) You tried to apply the C<:param> attribute to an array or hash field. diff --git a/pod/perlmod.pod b/pod/perlmod.pod index 63516e55e2bb..117142f2e94f 100644 --- a/pod/perlmod.pod +++ b/pod/perlmod.pod @@ -69,6 +69,21 @@ colon: C<$Package::Variable>. If the package name is null, the C
package is assumed. That is, C<$::sail> is equivalent to C<$main::sail>. +The old package delimiter was a single quote, but double colon is now the +preferred delimiter, in part because it's more readable to humans, and +in part because it's more readable to B macros. It also makes C++ +programmers feel like they know what's going on--as opposed to using the +single quote as separator, which was there to make Ada programmers feel +like they knew what was going on. Because the old-fashioned syntax is still +supported for backwards compatibility, if you try to use a string like +C<"This is $owner's house">, you'll be accessing C<$owner::s>; that is, +the $s variable in package C, which is probably not what you meant. +Use braces to disambiguate, as in C<"This is ${owner}'s house">. +X<::> X<'> + +Using C<'> as a package separator is deprecated and will be removed in +Perl 5.40. + Packages may themselves contain package separators, as in C<$OUTER::INNER::var>. This implies nothing about the order of name lookups, however. There are no relative packages: all symbols @@ -79,9 +94,6 @@ C<$OUTER::INNER::var>. C refers to a totally separate global package. The custom of treating package names as a hierarchy is very strong, but the language in no way enforces it. -Previously you could use C<'> as a package separator, this was removed -in Perl 5.42. - Only identifiers starting with letters (or underscore) are stored in a package's symbol table. All other symbols are kept in package C
, including all punctuation variables, like $_. In addition, diff --git a/proto.h b/proto.h index 64734e6d82e0..909cba273be3 100644 --- a/proto.h +++ b/proto.h @@ -4191,6 +4191,11 @@ Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STR #define PERL_ARGS_ASSERT_SCAN_WORD \ assert(s); assert(dest); assert(slp) +PERL_CALLCONV char * +Perl_scan_word6(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp, bool warn_tick); +#define PERL_ARGS_ASSERT_SCAN_WORD6 \ + assert(s); assert(dest); assert(slp) + PERL_CALLCONV U32 Perl_seed(pTHX); #define PERL_ARGS_ASSERT_SEED @@ -9251,7 +9256,7 @@ S_new_constant(pTHX_ const char *s, STRLEN len, const char *key, STRLEN keylen, assert(key); assert(sv) STATIC void -S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, bool is_utf8, bool check_dollar); +S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, bool is_utf8, bool check_dollar, bool tick_warn); # define PERL_ARGS_ASSERT_PARSE_IDENT \ assert(s); assert(d); assert(e) diff --git a/t/comp/package.t b/t/comp/package.t index d3e8850a4511..7b19513bddf2 100644 --- a/t/comp/package.t +++ b/t/comp/package.t @@ -18,11 +18,14 @@ $bar = 4; { package ABC; + no warnings qw(syntax deprecated); $blurfl = 5; - $main::a = $::b; + $main'a = $'b; +} +{ + no warnings qw(syntax deprecated); + $ABC'dyick = 6; } - -$ABC::dyick = 6; $xyz = 2; @@ -33,10 +36,13 @@ $ABC = join(':', sort(keys %ABC::)); if ('a' lt 'A') { print $xyz eq 'bar:main:new:xyz:ABC' ? "ok 1\n" : "not ok 1 '$xyz'\n"; } else { - print $xyz eq 'ABC:bar:main:new:xyz' ? "ok 1\n" : "not ok 1 '$xyz'\n"; + print $xyz eq 'ABC:BEGIN:bar:main:new:xyz' ? "ok 1\n" : "not ok 1 '$xyz'\n"; +} +print $ABC eq 'BEGIN:blurfl:dyick' ? "ok 2\n" : "not ok 2 '$ABC'\n"; +{ + no warnings qw(syntax deprecated); + print $main'blurfl == 123 ? "ok 3\n" : "not ok 3\n"; } -print $ABC eq 'blurfl:dyick' ? "ok 2\n" : "not ok 2 '$ABC'\n"; -print $main::blurfl == 123 ? "ok 3\n" : "not ok 3\n"; package ABC; diff --git a/t/comp/parser.t b/t/comp/parser.t index 14344cd686f0..20ecc7ac11c5 100644 --- a/t/comp/parser.t +++ b/t/comp/parser.t @@ -8,7 +8,7 @@ BEGIN { chdir 't' if -d 't'; } -print "1..189\n"; +print "1..191\n"; sub failed { my ($got, $expected, $name) = @_; @@ -222,12 +222,8 @@ EOF # tests for "Bad name" eval q{ foo::$bar }; like( $@, qr/Bad name after foo::/, 'Bad name after foo::' ); -{ - # since ' is no longer usable in symbols, the error is no longer "Bad name" - no warnings "syntax"; # suppress String found where operator expeected - eval q{ foo''bar }; - like( $@, qr/syntax error at \(eval \d+\) line 1, near "foo''/, 'Syntax error for foo\'' ); -} +eval q{ foo''bar }; +like( $@, qr/Bad name after foo'/, 'Bad name after foo\'' ); # test for ?: context error eval q{($a ? $x : ($y)) = 5}; @@ -372,11 +368,12 @@ like($@, qr/BEGIN failed--compilation aborted/, 'BEGIN 7' ); } { + no warnings; # [perl #113016] CORE::print::foo - sub CORE::print::foo { 43 } - sub CORE::foo::bar { 43 } + sub CORE'print'foo { 43 } # apostrophes intentional; do not tempt fate + sub CORE'foo'bar { 43 } is CORE::print::foo, 43, 'CORE::print::foo is not CORE::print ::foo'; - is scalar eval "CORE::foo::bar", 43, "CORE::foo'bar is not an error"; + is scalar eval "CORE::foo'bar", 43, "CORE::foo'bar is not an error"; } # bug #71748 @@ -454,6 +451,11 @@ END eval 's/${< ( EXPECT Bareword found where operator expected (Do you need to predeclare "isa"?) at - line 9, near "isa => 'Int" (Might be a runaway multi-line '' string starting on line 4) -syntax error at - line 9, near "isa => 'Int" -Execution of - aborted due to compilation errors. +Bad name after Int' at - line 9. ######## # NAME Bad name after :: (with other helpful messages) sub has{} @@ -612,18 +611,3 @@ syntax error at - line 2, near "[ ==" (Might be a runaway multi-line // string starting on line 1) Execution of - aborted due to compilation errors. -######## -# NAME tick in names: initial character of sub name -sub 'Hello'_he_said (_); -EXPECT -Illegal declaration of anonymous subroutine at - line 1. -######## -# NAME tick in names: initial character of format name - format 'one = -ok @<< - format 'foo still works -$test -. -EXPECT -syntax error at - line 2, near "ok @<< - format '" - (Might be a runaway multi-line '' string starting on line 1) -Execution of - aborted due to compilation errors. diff --git a/t/lib/warnings/toke b/t/lib/warnings/toke index 476108858e21..fc1c66378288 100644 --- a/t/lib/warnings/toke +++ b/t/lib/warnings/toke @@ -408,10 +408,6 @@ sort ("") EXPECT ######## -# NAME ' no longer is part of the symbol character set -# previously these would parse like: -# "${foo'bar}", but now they parse like "${foo}'bar" -# and any ' parsing for symbols is now gone, so no warning @foo::bar = 1..3; () = "$foo'bar"; () = "@foo'bar"; @@ -425,8 +421,19 @@ no warnings 'syntax', 'deprecated' ; () = "@foo'bar"; () = "$#foo'bar"; EXPECT +Old package separator used in string at - line 2. + (Did you mean "$foo\'bar" instead?) +Old package separator used in string at - line 3. + (Did you mean "@foo\'bar" instead?) +Old package separator used in string at - line 4. + (Did you mean "$#foo\'bar" instead?) +Old package separator used in string at - line 6. + (Did you mean "$foo\'bar" instead?) +Old package separator used in string at - line 7. + (Did you mean "@foo\'bar" instead?) +Old package separator used in string at - line 8. + (Did you mean "$#foo\'bar" instead?) ######## -# similar to the test above in that the parsing has changed use warnings 'syntax'; use utf8; @fooл::barл = 1..3; () = "$fooл'barл"; @@ -437,7 +444,12 @@ no warnings 'syntax', 'deprecated' ; () = "@fooл'barл"; () = "$#fooл'barл"; EXPECT -Possible unintended interpolation of @fooл in string at - line 5. +Old package separator used in string at - line 3. + (Did you mean "$fooл\'barл" instead?) +Old package separator used in string at - line 4. + (Did you mean "@fooл\'barл" instead?) +Old package separator used in string at - line 5. + (Did you mean "$#fooл\'barл" instead?) ######## # NAME deprecation of ' in names sub foo'bar { 1 } @@ -446,8 +458,11 @@ $a'b = 1; %a'd = (); package a'e; EXPECT -OPTION fatal -Illegal declaration of subroutine main::foo at - line 1. +Old package separator "'" deprecated at - line 1. +Old package separator "'" deprecated at - line 2. +Old package separator "'" deprecated at - line 3. +Old package separator "'" deprecated at - line 4. +Old package separator "'" deprecated at - line 5. ######## # toke.c use warnings 'ambiguous' ; diff --git a/t/op/magic.t b/t/op/magic.t index d13b6c5d8018..49e39b7c7203 100644 --- a/t/op/magic.t +++ b/t/op/magic.t @@ -5,7 +5,7 @@ BEGIN { chdir 't' if -d 't'; require './test.pl'; set_up_inc( '../lib' ); - plan (tests => 209); # some tests are run in BEGIN block + plan (tests => 208); # some tests are run in BEGIN block } # Test that defined() returns true for magic variables created on the fly, @@ -676,14 +676,6 @@ foreach my $sig (qw(__WARN__ INT)) { is delete $SIG{$sig}, undef, "$sig remains gone"; } -# test Perl_magic_setsig main:: qualification -# this previously did it for names containing ' -{ - local $SIG{INT} = "foo'bar"; - is($SIG{INT}, "main::foo'bar", - "' in signal handler name no longer a package separator"); -} - # And now one which doesn't exist; { no warnings 'signal'; diff --git a/t/op/method.t b/t/op/method.t index ddadb87420e6..eaa129aee1c7 100644 --- a/t/op/method.t +++ b/t/op/method.t @@ -13,7 +13,7 @@ BEGIN { use strict; no warnings 'once'; -plan(tests => 161); +plan(tests => 163); { # RT #126042 &{1==1} * &{1==1} would crash @@ -253,6 +253,12 @@ sub OtherSouper::method { "Isidore Ropen, Draft Manager" } my @ret = $o->SUPER::method('whatever'); ::is $ret[0], $o, 'object passed to SUPER::method'; ::is $ret[1], 'whatever', 'argument passed to SUPER::method'; + { + no warnings qw(syntax deprecated); + @ret = $o->SUPER'method('whatever'); + } + ::is $ret[0], $o, "object passed to SUPER'method"; + ::is $ret[1], 'whatever', "argument passed to SUPER'method"; @ret = Saab->SUPER::method; ::is $ret[0], 'Saab', "package name passed to SUPER::method"; @ret = OtherSaab->SUPER::method; diff --git a/t/op/ref.t b/t/op/ref.t index 76b55b24ad9d..3cf6ab047259 100644 --- a/t/op/ref.t +++ b/t/op/ref.t @@ -272,8 +272,10 @@ is (join('', sort values %$anonhash2), 'BARXYZ'); # Test bless operator. package MYHASH; -$object = bless $main::anonhash2; - +{ + no warnings qw(syntax deprecated); + $object = bless $main'anonhash2; +} main::is (ref $object, 'MYHASH'); main::is ($object->{ABC}, 'XYZ'); @@ -297,7 +299,10 @@ sub mymethod { $string = "bad"; $object = "foo"; $string = "good"; -$main::anonhash2 = "foo"; +{ + no warnings qw(syntax deprecated); + $main'anonhash2 = "foo"; +} $string = ""; DESTROY { @@ -314,7 +319,10 @@ package OBJ; @ISA = ('BASEOBJ'); -$main::object = bless {FOO => 'foo', BAR => 'bar'}; +{ + no warnings qw(syntax deprecated); + $main'object = bless {FOO => 'foo', BAR => 'bar'}; +} package main; @@ -327,10 +335,13 @@ is ($object->doit("BAR"), 'bar'); $foo = doit $object "FOO"; main::is ($foo, 'foo'); -sub BASEOBJ::doit { - local $ref = shift; - die "Not an OBJ" unless ref $ref eq 'OBJ'; - $ref->{shift()}; +{ + no warnings qw(syntax deprecated); + sub BASEOBJ'doit { + local $ref = shift; + die "Not an OBJ" unless ref $ref eq 'OBJ'; + $ref->{shift()}; + } } package UNIVERSAL; diff --git a/t/op/sort.t b/t/op/sort.t index 19c99961ac05..bdb965dcee63 100644 --- a/t/op/sort.t +++ b/t/op/sort.t @@ -240,7 +240,7 @@ eval <<'CODE'; no warnings qw(deprecated syntax); my @result = sort main'Backwards 'one', 'two'; CODE -cmp_ok($@,'ne','',q(old skool package)); +cmp_ok($@,'eq','',q(old skool package)); eval <<'CODE'; # "sort 'one', 'two'" should not try to parse "'one" as a sort sub diff --git a/t/op/stash.t b/t/op/stash.t index f10834adcc87..a507c4239db1 100644 --- a/t/op/stash.t +++ b/t/op/stash.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc( qw(../lib) ); } -plan( tests => 54 ); +plan( tests => 55 ); # Used to segfault (bug #15479) fresh_perl_like( @@ -301,6 +301,10 @@ fresh_perl_is( 'packages ending with :: are self-consistent'; } +# [perl #88138] ' not equivalent to :: before a null +${"a'\0b"} = "c"; +is ${"a::\0b"}, "c", "' is equivalent to :: before a null"; + # [perl #101486] Clobbering the current package ok eval ' package Do; diff --git a/t/op/stash_parse_gv.t b/t/op/stash_parse_gv.t index 465480e331eb..9e143d979e15 100644 --- a/t/op/stash_parse_gv.t +++ b/t/op/stash_parse_gv.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc(qw(../lib)); } -plan( tests => 3 ); +plan( tests => 5 ); my $long = 'x' x 100; my $short = 'abcd'; @@ -14,7 +14,9 @@ my $short = 'abcd'; my @tests = ( [ $long, 'long package name: one word' ], [ join( '::', $long, $long ), 'long package name: multiple words' ], + [ join( q['], $long, $long ), q[long package name: multiple words using "'" separator] ], [ join( '::', $long, $short, $long ), 'long & short package name: multiple words' ], + [ join( q['], $long, $short, $long ), q[long & short package name: multiple words using "'" separator] ], ); foreach my $t (@tests) { diff --git a/t/uni/package.t b/t/uni/package.t index b615bf01120a..d4e69ca38044 100644 --- a/t/uni/package.t +++ b/t/uni/package.t @@ -9,6 +9,9 @@ BEGIN { plan (tests => 18); +# Works on either ASCII or EBCDIC +my $prefix = ("a" lt "A") ? "bar:BEGIN" : "BEGIN:bar"; + use utf8; use open qw( :utf8 :std ); @@ -34,17 +37,23 @@ ok 1, "sanity check. If we got this far, UTF-8 in package names is legal."; $ㄅĽuṞfⳐ = 5; } - $압Ƈ::d읯ⱪ = 6; + { + no warnings qw(syntax deprecated); + $압Ƈ'd읯ⱪ = 6; #' + } $ꑭʑ = 2; $ꑭʑ = join(':', sort(keys %ꑭʑ::)); $압Ƈ = join(':', sort(keys %압Ƈ::)); - ::is $ꑭʑ, "bar:ニュー:ꑭʑ:압Ƈ", "comp/stash.t test 1"; + ::is $ꑭʑ, "$prefix:ニュー:ꑭʑ:압Ƈ", "comp/stash.t test 1"; ::is $압Ƈ, "d읯ⱪ:ㄅĽuṞfⳐ", "comp/stash.t test 2"; - ::is $main::ㄅĽuṞfⳐ, 123, "comp/stash.t test 3"; + { + no warnings qw(syntax deprecated); + ::is $main'ㄅĽuṞfⳐ, 123, "comp/stash.t test 3"; + } package 압Ƈ; diff --git a/t/uni/parser.t b/t/uni/parser.t index 6fdd99749163..d3aa74527224 100644 --- a/t/uni/parser.t +++ b/t/uni/parser.t @@ -187,12 +187,8 @@ is ${"main::\345\225\217"}, undef, "..and using the encoded form doesn't"; # tests for "Bad name" eval q{ Foo::$bar }; like( $@, qr/Bad name after Foo::/, 'Bad name after Foo::' ); -{ - # since ' is no longer usable in symbols, the error is no longer "Bad name" - no warnings "syntax"; # suppress String found where operator expeected - eval q{ Foo''bar }; - like( $@, qr/syntax error at \(eval \d+\) line 1, near \"Foo\'\'/, 'Syntax error for Foo\'' ); -} +eval q{ Foo''bar }; +like( $@, qr/Bad name after Foo'/, 'Bad name after Foo\'' ); { no warnings 'utf8'; diff --git a/t/uni/stash.t b/t/uni/stash.t index 7bfdc6cac3c5..a069aa111e23 100644 --- a/t/uni/stash.t +++ b/t/uni/stash.t @@ -13,7 +13,7 @@ BEGIN { use utf8; use open qw( :utf8 :std ); -plan( tests => 48 ); +plan( tests => 49 ); #These come from op/my_stash.t { @@ -283,4 +283,8 @@ plan( tests => 48 ); ok eval { Bèàr::::bàz() }, 'packages ending with :: are self-consistent'; } + + # [perl #88138] ' not equivalent to :: before a null + ${"à'\0b"} = "c"; + is ${"à::\0b"}, "c", "' is equivalent to :: before a null"; } diff --git a/t/uni/variables.t b/t/uni/variables.t index c5284de3e9f5..2c18951a1a26 100644 --- a/t/uni/variables.t +++ b/t/uni/variables.t @@ -14,7 +14,7 @@ use utf8; use open qw( :utf8 :std ); no warnings qw(misc reserved); -plan (tests => 66879); +plan (tests => 66880); # ${single:colon} should not be treated as a simple variable, but as a # block with a label inside. @@ -35,11 +35,16 @@ plan (tests => 66879); ); } -# and ${yadda::etc} should both work under strict +# ${yadda'etc} and ${yadda::etc} should both work under strict { local $@; eval q; is($@, '', q<${package::var} works>); + + no warnings qw(syntax deprecated); + local $@; + eval q; + is($@, '', q<...as does ${package'var}>); } # The first character in ${...} should respect the rules diff --git a/toke.c b/toke.c index 0ff92d2b256f..62ae6eb5cc67 100644 --- a/toke.c +++ b/toke.c @@ -2308,7 +2308,7 @@ S_force_word(pTHX_ char *start, int token, int check_keyword, int allow_pack) if ( isIDFIRST_lazy_if_safe(s, PL_bufend, UTF) || (allow_pack && *s == ':' && s[1] == ':') ) { - s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, allow_pack, &len); + s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, allow_pack, &len, allow_pack); if (check_keyword) { char *s2 = PL_tokenbuf; STRLEN len2 = len; @@ -4847,7 +4847,7 @@ S_intuit_method(pTHX_ char *start, SV *ioname, CV *cv) return *s == '(' ? METHCALL : METHCALL0; } - s = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len); + s = scan_word6(s, tmpbuf, sizeof tmpbuf, TRUE, &len, FALSE); /* start is the beginning of the possible filehandle/object, * and s is the end of it * tmpbuf is a copy of it (but with single quotes as double colons) @@ -5296,7 +5296,7 @@ yyl_sigvar(pTHX_ char *s) /* read var name, including sigil, into PL_tokenbuf */ PL_tokenbuf[0] = sigil; parse_ident(&s, &dest, dest + sizeof(PL_tokenbuf) - 1, - 0, cBOOL(UTF), FALSE); + 0, cBOOL(UTF), FALSE, FALSE); *dest = '\0'; assert(PL_tokenbuf[1]); /* we have a variable name */ } @@ -5519,7 +5519,7 @@ yyl_dollar(pTHX_ char *s) char tmpbuf[sizeof PL_tokenbuf]; int t2; STRLEN len; - scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len); + scan_word6(s, tmpbuf, sizeof tmpbuf, TRUE, &len, FALSE); if ((t2 = keyword(tmpbuf, len, 0))) { /* binary operators exclude handle interpretations */ switch (t2) { @@ -5585,11 +5585,13 @@ yyl_sub(pTHX_ char *s, const int key) PL_parser->sig_seen = FALSE; if ( isIDFIRST_lazy_if_safe(s, PL_bufend, UTF) + || *s == '\'' || (*s == ':' && s[1] == ':')) { PL_expect = XATTRBLOCK; - d = scan_word(s, tmpbuf, sizeof PL_tokenbuf - 1, TRUE, &len); + d = scan_word6(s, tmpbuf, sizeof PL_tokenbuf - 1, TRUE, + &len, TRUE); if (key == KEY_format) format_name = S_newSV_maybe_utf8(aTHX_ s, d - s); *PL_tokenbuf = '&'; @@ -6181,7 +6183,7 @@ yyl_colon(pTHX_ char *s) I32 tmp; SV *sv; STRLEN len; - char *d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); + char *d = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len, 0))) { if (tmp < 0) tmp = -tmp; switch (tmp) { @@ -6360,8 +6362,8 @@ yyl_leftcurly(pTHX_ char *s, const U8 formbrack) } if (d < PL_bufend && isIDFIRST_lazy_if_safe(d, PL_bufend, UTF)) { STRLEN len; - d = scan_word(d, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, - FALSE, &len); + d = scan_word6(d, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, + FALSE, &len, FALSE); while (d < PL_bufend && SPACE_OR_TAB(*d)) d++; if (*d == '}') { @@ -7166,7 +7168,7 @@ yyl_foreach(pTHX_ char *s) /* skip optional package name, as in "for my abc $x (..)" */ if (UNLIKELY(isIDFIRST_lazy_if_safe(p, PL_bufend, UTF))) { STRLEN len; - p = scan_word(p, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len); + p = scan_word6(p, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len, TRUE); p = skipspace(p); paren_is_valid = FALSE; } @@ -7195,8 +7197,8 @@ yyl_do(pTHX_ char *s, I32 orig_keyword) char *d; STRLEN len; *PL_tokenbuf = '&'; - d = scan_word(s, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, - 1, &len); + d = scan_word6(s, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, + 1, &len, TRUE); if (len && memNEs(PL_tokenbuf+1, len, "CORE") && !keyword(PL_tokenbuf + 1, len, 0)) { SSize_t off = s-SvPVX(PL_linestr); @@ -7231,7 +7233,7 @@ yyl_my(pTHX_ char *s, I32 my) s = skipspace(s); if (isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) { STRLEN len; - s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len); + s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len, TRUE); if (memEQs(PL_tokenbuf, len, "sub")) return yyl_sub(aTHX_ s, my); PL_in_my_stash = find_in_my_stash(PL_tokenbuf, len); @@ -7701,17 +7703,18 @@ yyl_just_a_word(pTHX_ char *s, STRLEN len, I32 orig_keyword, struct code c) /* Get the rest if it looks like a package qualifier */ - if (*s == ':' && s[1] == ':') { + if (*s == '\'' || (*s == ':' && s[1] == ':')) { STRLEN morelen; - s = scan_word(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len, - TRUE, &morelen); + s = scan_word6(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len, + TRUE, &morelen, TRUE); if (no_op_error) { S_warn_expect_operator(aTHX_ "Bareword",s,FALSE); no_op_error = FALSE; } if (!morelen) - Perl_croak(aTHX_ "Bad name after %" UTF8f "::", - UTF8fARG(UTF, len, PL_tokenbuf)); + Perl_croak(aTHX_ "Bad name after %" UTF8f "%s", + UTF8fARG(UTF, len, PL_tokenbuf), + *s == '\'' ? "'" : "::"); len += morelen; pkgname = 1; } @@ -8433,7 +8436,7 @@ yyl_word_or_keyword(pTHX_ char *s, STRLEN len, I32 key, I32 orig_keyword, struct s = skipspace(s); if (isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) { const char *t; - char *d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); + char *d = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); for (t=d; isSPACE(*t);) t++; if ( *t && memCHRs("|&*+-=!?:.", *t) && ckWARN_d(WARN_PRECEDENCE) @@ -8856,17 +8859,18 @@ yyl_word_or_keyword(pTHX_ char *s, STRLEN len, I32 key, I32 orig_keyword, struct static int yyl_key_core(pTHX_ char *s, STRLEN len, struct code c) { + I32 key = 0; I32 orig_keyword = 0; STRLEN olen = len; char *d = s; s += 2; - s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); - if (*s == ':' && s[1] == ':') + s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); + if ((*s == ':' && s[1] == ':') + || (!(key = keyword(PL_tokenbuf, len, 1)) && *s == '\'')) { Copy(PL_bufptr, PL_tokenbuf, olen, char); return yyl_just_a_word(aTHX_ d, olen, 0, c); } - I32 key = keyword(PL_tokenbuf, len, 1); if (!key) Perl_croak(aTHX_ "CORE::%" UTF8f " is not a keyword", UTF8fARG(UTF, len, PL_tokenbuf)); @@ -8939,7 +8943,7 @@ yyl_keylookup(pTHX_ char *s, GV *gv) c.gv = gv; PL_bufptr = s; - s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); + s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); /* Some keywords can be followed by any delimiter, including ':' */ anydelim = word_takes_any_delimiter(PL_tokenbuf, len); @@ -10269,8 +10273,10 @@ S_new_constant(pTHX_ const char *s, STRLEN len, const char *key, STRLEN keylen, PERL_STATIC_INLINE void S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, - bool is_utf8, bool check_dollar) + bool is_utf8, bool check_dollar, bool tick_warn) { + int saw_tick = 0; + const char *olds = *s; PERL_ARGS_ASSERT_PARSE_IDENT; while (*s < PL_bufend) { @@ -10297,6 +10303,15 @@ S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, *(*d)++ = *(*s)++; } while (isWORDCHAR_A(**s) && *d < e); } + else if ( allow_package + && **s == '\'' + && isIDFIRST_lazy_if_safe((*s)+1, PL_bufend, is_utf8)) + { + *(*d)++ = ':'; + *(*d)++ = ':'; + (*s)++; + saw_tick++; + } else if (allow_package && **s == ':' && (*s)[1] == ':' /* Disallow things like Foo::$bar. For the curious, this is * the code path that triggers the "Bad name after" warning @@ -10309,24 +10324,66 @@ S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, else break; } + if (UNLIKELY(saw_tick && tick_warn && ckWARN2_d(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR))) { + if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) { + char *this_d; + char *d2; + Newx(this_d, *s - olds + saw_tick + 2, char); /* +2 for $# */ + d2 = this_d; + SAVEFREEPV(this_d); + + Perl_warner(aTHX_ packWARN2(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR), + "Old package separator used in string"); + if (olds[-1] == '#') + *d2++ = olds[-2]; + *d2++ = olds[-1]; + while (olds < *s) { + if (*olds == '\'') { + *d2++ = '\\'; + *d2++ = *olds++; + } + else + *d2++ = *olds++; + } + Perl_warner(aTHX_ packWARN(WARN_SYNTAX), + "\t(Did you mean \"%" UTF8f "\" instead?)\n", + UTF8fARG(is_utf8, d2-this_d, this_d)); + } + else { + Perl_warner(aTHX_ packWARN2(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR), + "Old package separator \"'\" deprecated"); + } + } return; } +/* Returns a NUL terminated string, with the length of the string written to + *slp + + scan_word6() may be removed once ' in names is removed. + */ char * -Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp) +Perl_scan_word6(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp, bool warn_tick) { - PERL_ARGS_ASSERT_SCAN_WORD; - char *d = dest; char * const e = d + destlen - 3; /* two-character token, ending NUL */ bool is_utf8 = cBOOL(UTF); - parse_ident(&s, &d, e, allow_package, is_utf8, TRUE); + PERL_ARGS_ASSERT_SCAN_WORD6; + + parse_ident(&s, &d, e, allow_package, is_utf8, TRUE, warn_tick); *d = '\0'; *slp = d - dest; return s; } +char * +Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp) +{ + PERL_ARGS_ASSERT_SCAN_WORD; + return scan_word6(s, dest, destlen, allow_package, slp, FALSE); +} + /* scan s and extract an identifier ($var) from it if possible * into dest. * XXX: This function has subtle implications on parsing, and @@ -10362,7 +10419,7 @@ S_scan_ident(pTHX_ char *s, char *dest, STRLEN destlen, I32 ck_uni) Perl_croak(aTHX_ ident_var_zero_multi_digit); } else { /* See if it is a "normal" identifier */ - parse_ident(&s, &d, e, 1, is_utf8, FALSE); + parse_ident(&s, &d, e, 1, is_utf8, FALSE, TRUE); } *d = '\0'; d = dest; @@ -10487,7 +10544,7 @@ S_scan_ident(pTHX_ char *s, char *dest, STRLEN destlen, I32 ck_uni) (the later check for } being at the expected point will trap cases where this doesn't pan out.) */ d += is_utf8 ? UTF8SKIP(d) : 1; - parse_ident(&s, &d, e, 1, is_utf8, TRUE); + parse_ident(&s, &d, e, 1, is_utf8, TRUE, TRUE); *d = '\0'; } else { /* caret word: ${^Foo} ${^CAPTURE[0]} */ @@ -11434,7 +11491,7 @@ S_scan_inputsymbol(pTHX_ char *start) if (*d == '$' && d[1]) d++; /* allow or */ - while (isWORDCHAR_lazy_if_safe(d, e, UTF) || *d == ':') { + while (isWORDCHAR_lazy_if_safe(d, e, UTF) || *d == '\'' || *d == ':') { d += UTF ? UTF8SKIP(d) : 1; } @@ -13779,7 +13836,7 @@ Perl_parse_label(pTHX_ U32 flags) t = s = PL_bufptr; if (!isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) goto no_label; - t = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &wlen); + t = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &wlen, FALSE); if (word_takes_any_delimiter(s, wlen)) goto no_label; bufptr_pos = s - SvPVX(PL_linestr); From e9030e26e7fdaf18f4a8b3e1291377ee2537db04 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Wed, 9 Oct 2024 10:04:11 +1100 Subject: [PATCH 4/9] remove deprecation of apostrophe in symbol I'm a little hesitant over the removal of the warning identifier, since it means code that suppressed the warning in 5.38 and 5.40 will now see an error, but porting/deprecation complained when I removed the documentation from pod/perldeprecation.pod but left the warning in. An alternative would be to add a "Cancelled Removals" to perldeprecation. --- lib/warnings.pm | 35 +++++++++++--------------- pod/perldeprecation.pod | 10 -------- pod/perldiag.pod | 16 ------------ regen/warnings.pl | 4 +-- t/lib/warnings/toke | 56 ----------------------------------------- toke.c | 30 ---------------------- warnings.h | 11 +++----- 7 files changed, 18 insertions(+), 144 deletions(-) diff --git a/lib/warnings.pm b/lib/warnings.pm index 11c09eaa0a28..7edc55640b51 100644 --- a/lib/warnings.pm +++ b/lib/warnings.pm @@ -5,7 +5,7 @@ package warnings; -our $VERSION = "1.70"; +our $VERSION = "1.71"; # Verify that we're called correctly so that warnings will work. # Can't use Carp, since Carp uses us! @@ -124,17 +124,14 @@ our %Offsets = ( # Warnings Categories added in Perl 5.037 'experimental::class' => 150, - # Warnings Categories added in Perl 5.037009 - 'deprecated::apostrophe_as_package_separator'=> 152, - # Warnings Categories added in Perl 5.03701 - 'deprecated::smartmatch' => 154, + 'deprecated::smartmatch' => 152, # Warnings Categories added in Perl 5.039002 - 'deprecated::missing_import_called_with_args'=> 156, + 'deprecated::missing_import_called_with_args'=> 154, # Warnings Categories added in Perl 5.039008 - 'deprecated::subsequent_use_version'=> 158, + 'deprecated::subsequent_use_version'=> 156, ); our %Bits = ( @@ -144,14 +141,13 @@ our %Bits = ( 'closed' => "\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [6] 'closure' => "\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [1] 'debugging' => "\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [22] - 'deprecated' => "\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x10\x00\x00\x14\x55", # [2,48,49,62,73,74,76..79] - 'deprecated::apostrophe_as_package_separator'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", # [76] + 'deprecated' => "\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x10\x00\x00\x14\x15", # [2,48,49,62,73,74,76..78] 'deprecated::delimiter_will_be_paired'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00", # [74] 'deprecated::dot_in_inc' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00", # [62] 'deprecated::goto_construct' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00", # [48] - 'deprecated::missing_import_called_with_args'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", # [78] - 'deprecated::smartmatch' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", # [77] - 'deprecated::subsequent_use_version'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40", # [79] + 'deprecated::missing_import_called_with_args'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", # [77] + 'deprecated::smartmatch' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", # [76] + 'deprecated::subsequent_use_version'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", # [78] 'deprecated::unicode_property_name' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00", # [49] 'deprecated::version_downgrade' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00", # [73] 'digit' => "\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [31] @@ -227,14 +223,13 @@ our %DeadBits = ( 'closed' => "\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [6] 'closure' => "\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [1] 'debugging' => "\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [22] - 'deprecated' => "\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x20\x00\x00\x28\xaa", # [2,48,49,62,73,74,76..79] - 'deprecated::apostrophe_as_package_separator'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", # [76] + 'deprecated' => "\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x20\x00\x00\x28\x2a", # [2,48,49,62,73,74,76..78] 'deprecated::delimiter_will_be_paired'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00", # [74] 'deprecated::dot_in_inc' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00", # [62] 'deprecated::goto_construct' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00", # [48] - 'deprecated::missing_import_called_with_args'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20", # [78] - 'deprecated::smartmatch' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08", # [77] - 'deprecated::subsequent_use_version'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80", # [79] + 'deprecated::missing_import_called_with_args'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08", # [77] + 'deprecated::smartmatch' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", # [76] + 'deprecated::subsequent_use_version'=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20", # [78] 'deprecated::unicode_property_name' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00", # [49] 'deprecated::version_downgrade' => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00", # [73] 'digit' => "\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # [31] @@ -318,8 +313,8 @@ our %NoOp = ( # These are used by various things, including our own tests our $NONE = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -our $DEFAULT = "\x10\x01\x00\x00\x00\x50\x04\x00\x00\x00\x00\x00\x05\x00\x15\x14\x55\x55\x54\x55"; # [2,4,22,23,25,48,49,56..58,61,62,64..71,73..79] -our $LAST_BIT = 160 ; +our $DEFAULT = "\x10\x01\x00\x00\x00\x50\x04\x00\x00\x00\x00\x00\x05\x00\x15\x14\x55\x55\x54\x15"; # [2,4,22,23,25,48,49,56..58,61,62,64..71,73..78] +our $LAST_BIT = 158 ; our $BYTES = 20 ; sub Croaker @@ -922,8 +917,6 @@ The current hierarchy is: | +- deprecated ----+ | | - | +- deprecated::apostrophe_as_package_separator - | | | +- deprecated::delimiter_will_be_paired | | | +- deprecated::dot_in_inc diff --git a/pod/perldeprecation.pod b/pod/perldeprecation.pod index 552624b536a0..b06797d82b58 100644 --- a/pod/perldeprecation.pod +++ b/pod/perldeprecation.pod @@ -97,16 +97,6 @@ your restraint. Category: "deprecated::goto_construct" -=head3 Use of C<'> as a global name separator - -Perl allows use of C<'> instead of C<::> to replace the parts of a -package or global variable name, for example C and C are -equivalent. - -C<'> will no longer be recognized as a name separator in Perl 5.42. - -Category: "deprecated::apostrophe_as_package_separator" - =head2 Perl 5.40 =head3 Downgrading a C to below v5.11 diff --git a/pod/perldiag.pod b/pod/perldiag.pod index ebbe174eb460..ab08994aa0a4 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -4759,22 +4759,6 @@ Cing a file, or when seeking past the end of a scalar opened for I/O (in anticipation of future reads and to imitate the behavior with real files). -=item Old package separator "'" deprecated - -(D deprecated::apostrophe_as_package_separator, syntax) You used the old package -separator "'" in a variable, subroutine or package name. Support for the -old package separator will be removed in Perl 5.42. - -=item Old package separator used in string - -(D deprecated::apostrophe_as_package_separator, syntax) You used the old package -separator, "'", in a variable named inside a double-quoted string; e.g., -C<"In $name's house">. This is equivalent to C<"In $name::s house">. If -you meant the former, put a backslash before the apostrophe -(C<"In $name\'s house">). - -Support for the old package separator will be removed in Perl 5.42. - =item Only scalar fields can take a :param attribute (F) You tried to apply the C<:param> attribute to an array or hash field. diff --git a/regen/warnings.pl b/regen/warnings.pl index a7084f5827a5..b39c4ad177c0 100644 --- a/regen/warnings.pl +++ b/regen/warnings.pl @@ -16,7 +16,7 @@ # # This script is normally invoked from regen.pl. -$VERSION = '1.70'; +$VERSION = '1.71'; BEGIN { require './regen/regen_lib.pl'; @@ -80,8 +80,6 @@ BEGIN 'deprecated::dot_in_inc' => [ 5.025011, DEFAULT_ON], 'deprecated::version_downgrade' => [ 5.035009, DEFAULT_ON], 'deprecated::delimiter_will_be_paired' => [ 5.035010, DEFAULT_ON], - 'deprecated::apostrophe_as_package_separator' - => [ 5.037009, DEFAULT_ON], 'deprecated::smartmatch' => [ 5.037010, DEFAULT_ON], 'deprecated::missing_import_called_with_args' => [ 5.039002, DEFAULT_ON], diff --git a/t/lib/warnings/toke b/t/lib/warnings/toke index fc1c66378288..054a740bd397 100644 --- a/t/lib/warnings/toke +++ b/t/lib/warnings/toke @@ -407,62 +407,6 @@ no warnings 'syntax' ; sort ("") EXPECT -######## -@foo::bar = 1..3; -() = "$foo'bar"; -() = "@foo'bar"; -() = "$#foo'bar"; -use warnings 'syntax'; -() = "$foo'bar"; -() = "@foo'bar"; -() = "$#foo'bar"; -no warnings 'syntax', 'deprecated' ; -() = "$foo'bar"; -() = "@foo'bar"; -() = "$#foo'bar"; -EXPECT -Old package separator used in string at - line 2. - (Did you mean "$foo\'bar" instead?) -Old package separator used in string at - line 3. - (Did you mean "@foo\'bar" instead?) -Old package separator used in string at - line 4. - (Did you mean "$#foo\'bar" instead?) -Old package separator used in string at - line 6. - (Did you mean "$foo\'bar" instead?) -Old package separator used in string at - line 7. - (Did you mean "@foo\'bar" instead?) -Old package separator used in string at - line 8. - (Did you mean "$#foo\'bar" instead?) -######## -use warnings 'syntax'; use utf8; -@fooл::barл = 1..3; -() = "$fooл'barл"; -() = "@fooл'barл"; -() = "$#fooл'barл"; -no warnings 'syntax', 'deprecated' ; -() = "$fooл'barл"; -() = "@fooл'barл"; -() = "$#fooл'barл"; -EXPECT -Old package separator used in string at - line 3. - (Did you mean "$fooл\'barл" instead?) -Old package separator used in string at - line 4. - (Did you mean "@fooл\'barл" instead?) -Old package separator used in string at - line 5. - (Did you mean "$#fooл\'barл" instead?) -######## -# NAME deprecation of ' in names -sub foo'bar { 1 } -$a'b = 1; -@a'c = (); -%a'd = (); -package a'e; -EXPECT -Old package separator "'" deprecated at - line 1. -Old package separator "'" deprecated at - line 2. -Old package separator "'" deprecated at - line 3. -Old package separator "'" deprecated at - line 4. -Old package separator "'" deprecated at - line 5. ######## # toke.c use warnings 'ambiguous' ; diff --git a/toke.c b/toke.c index 62ae6eb5cc67..54c688d7db69 100644 --- a/toke.c +++ b/toke.c @@ -10324,36 +10324,6 @@ S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, else break; } - if (UNLIKELY(saw_tick && tick_warn && ckWARN2_d(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR))) { - if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) { - char *this_d; - char *d2; - Newx(this_d, *s - olds + saw_tick + 2, char); /* +2 for $# */ - d2 = this_d; - SAVEFREEPV(this_d); - - Perl_warner(aTHX_ packWARN2(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR), - "Old package separator used in string"); - if (olds[-1] == '#') - *d2++ = olds[-2]; - *d2++ = olds[-1]; - while (olds < *s) { - if (*olds == '\'') { - *d2++ = '\\'; - *d2++ = *olds++; - } - else - *d2++ = *olds++; - } - Perl_warner(aTHX_ packWARN(WARN_SYNTAX), - "\t(Did you mean \"%" UTF8f "\" instead?)\n", - UTF8fARG(is_utf8, d2-this_d, this_d)); - } - else { - Perl_warner(aTHX_ packWARN2(WARN_SYNTAX, WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR), - "Old package separator \"'\" deprecated"); - } - } return; } diff --git a/warnings.h b/warnings.h index 3322ed821b6c..e4897b655beb 100644 --- a/warnings.h +++ b/warnings.h @@ -150,21 +150,17 @@ #define WARN_EXPERIMENTAL__CLASS 75 -/* Warnings Categories added in Perl 5.037009 */ - -#define WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR 76 - /* Warnings Categories added in Perl 5.03701 */ -#define WARN_DEPRECATED__SMARTMATCH 77 +#define WARN_DEPRECATED__SMARTMATCH 76 /* Warnings Categories added in Perl 5.039002 */ -#define WARN_DEPRECATED__MISSING_IMPORT_CALLED_WITH_ARGS 78 +#define WARN_DEPRECATED__MISSING_IMPORT_CALLED_WITH_ARGS 77 /* Warnings Categories added in Perl 5.039008 */ -#define WARN_DEPRECATED__SUBSEQUENT_USE_VERSION 79 +#define WARN_DEPRECATED__SUBSEQUENT_USE_VERSION 78 #define WARNsize 20 #define WARN_ALLstring "\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125" #define WARN_NONEstring "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" @@ -355,7 +351,6 @@ category parameters passed. =for apidoc Amnh||WARN_DEPRECATED__VERSION_DOWNGRADE =for apidoc Amnh||WARN_DEPRECATED__DELIMITER_WILL_BE_PAIRED =for apidoc Amnh||WARN_EXPERIMENTAL__CLASS -=for apidoc Amnh||WARN_DEPRECATED__APOSTROPHE_AS_PACKAGE_SEPARATOR =for apidoc Amnh||WARN_DEPRECATED__SMARTMATCH =for apidoc Amnh||WARN_DEPRECATED__MISSING_IMPORT_CALLED_WITH_ARGS =for apidoc Amnh||WARN_DEPRECATED__SUBSEQUENT_USE_VERSION From c4ec484bde00f6f7272a07cc3490d0d31becee9b Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Wed, 9 Oct 2024 11:00:11 +1100 Subject: [PATCH 5/9] Add the apostrophe_as_package_separator feature to feature.pm --- feature.h | 95 ++++++++++++++++++++----------- lib/feature.pm | 140 ++++++++++++++++++++++++++++------------------ regen/feature.pl | 24 ++++++-- t/lib/feature/api | 8 +-- 4 files changed, 170 insertions(+), 97 deletions(-) diff --git a/feature.h b/feature.h index a7c0b0568c94..c5e85c5d2a8b 100644 --- a/feature.h +++ b/feature.h @@ -12,27 +12,28 @@ #define HINT_FEATURE_SHIFT 26 -#define FEATURE_BAREWORD_FILEHANDLES_BIT 0x0001 -#define FEATURE_BITWISE_BIT 0x0002 -#define FEATURE_CLASS_BIT 0x0004 -#define FEATURE___SUB___BIT 0x0008 -#define FEATURE_MYREF_BIT 0x0010 -#define FEATURE_DEFER_BIT 0x0020 -#define FEATURE_EVALBYTES_BIT 0x0040 -#define FEATURE_MORE_DELIMS_BIT 0x0080 -#define FEATURE_FC_BIT 0x0100 -#define FEATURE_INDIRECT_BIT 0x0200 -#define FEATURE_ISA_BIT 0x0400 -#define FEATURE_MODULE_TRUE_BIT 0x0800 -#define FEATURE_MULTIDIMENSIONAL_BIT 0x1000 -#define FEATURE_POSTDEREF_QQ_BIT 0x2000 -#define FEATURE_REFALIASING_BIT 0x4000 -#define FEATURE_SAY_BIT 0x8000 -#define FEATURE_SIGNATURES_BIT 0x10000 -#define FEATURE_STATE_BIT 0x20000 -#define FEATURE_TRY_BIT 0x40000 -#define FEATURE_UNIEVAL_BIT 0x80000 -#define FEATURE_UNICODE_BIT 0x100000 +#define FEATURE_APOS_AS_NAME_SEP_BIT 0x0001 +#define FEATURE_BAREWORD_FILEHANDLES_BIT 0x0002 +#define FEATURE_BITWISE_BIT 0x0004 +#define FEATURE_CLASS_BIT 0x0008 +#define FEATURE___SUB___BIT 0x0010 +#define FEATURE_MYREF_BIT 0x0020 +#define FEATURE_DEFER_BIT 0x0040 +#define FEATURE_EVALBYTES_BIT 0x0080 +#define FEATURE_MORE_DELIMS_BIT 0x0100 +#define FEATURE_FC_BIT 0x0200 +#define FEATURE_INDIRECT_BIT 0x0400 +#define FEATURE_ISA_BIT 0x0800 +#define FEATURE_MODULE_TRUE_BIT 0x1000 +#define FEATURE_MULTIDIMENSIONAL_BIT 0x2000 +#define FEATURE_POSTDEREF_QQ_BIT 0x4000 +#define FEATURE_REFALIASING_BIT 0x8000 +#define FEATURE_SAY_BIT 0x10000 +#define FEATURE_SIGNATURES_BIT 0x20000 +#define FEATURE_STATE_BIT 0x40000 +#define FEATURE_TRY_BIT 0x80000 +#define FEATURE_UNIEVAL_BIT 0x100000 +#define FEATURE_UNICODE_BIT 0x200000 #define FEATURE_BUNDLE_DEFAULT 0 #define FEATURE_BUNDLE_510 1 @@ -43,6 +44,7 @@ #define FEATURE_BUNDLE_535 6 #define FEATURE_BUNDLE_537 7 #define FEATURE_BUNDLE_539 8 +#define FEATURE_BUNDLE_541 9 #define FEATURE_BUNDLE_CUSTOM (HINT_FEATURE_MASK >> HINT_FEATURE_SHIFT) /* this is preserved for testing and asserts */ @@ -65,7 +67,7 @@ #define FEATURE_FC_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_515 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_FC_BIT)) \ ) @@ -73,7 +75,7 @@ #define FEATURE_ISA_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_535 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_ISA_BIT)) \ ) @@ -81,14 +83,15 @@ #define FEATURE_SAY_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_510 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_SAY_BIT)) \ ) #define FEATURE_TRY_IS_ENABLED \ ( \ - CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_539 \ + (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_539 && \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_TRY_BIT)) \ ) @@ -108,7 +111,7 @@ #define FEATURE_STATE_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_510 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_STATE_BIT)) \ ) @@ -116,7 +119,7 @@ #define FEATURE_BITWISE_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_527 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_BITWISE_BIT)) \ ) @@ -131,7 +134,7 @@ #define FEATURE_EVALBYTES_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_515 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_EVALBYTES_BIT)) \ ) @@ -139,7 +142,7 @@ #define FEATURE_SIGNATURES_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_535 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_SIGNATURES_BIT)) \ ) @@ -147,7 +150,7 @@ #define FEATURE___SUB___IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_515 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE___SUB___BIT)) \ ) @@ -155,7 +158,7 @@ #define FEATURE_MODULE_TRUE_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_537 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_MODULE_TRUE_BIT)) \ ) @@ -169,7 +172,7 @@ #define FEATURE_POSTDEREF_QQ_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_523 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_POSTDEREF_QQ_BIT)) \ ) @@ -177,7 +180,7 @@ #define FEATURE_UNIEVAL_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_515 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_UNIEVAL_BIT)) \ ) @@ -191,7 +194,7 @@ #define FEATURE_UNICODE_IS_ENABLED \ ( \ (CURRENT_FEATURE_BUNDLE >= FEATURE_BUNDLE_511 && \ - CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539) \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_541) \ || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ FEATURE_IS_ENABLED_MASK(FEATURE_UNICODE_BIT)) \ ) @@ -216,6 +219,13 @@ FEATURE_IS_ENABLED_MASK(FEATURE_MORE_DELIMS_BIT) \ ) +#define FEATURE_APOS_AS_NAME_SEP_IS_ENABLED \ + ( \ + CURRENT_FEATURE_BUNDLE <= FEATURE_BUNDLE_539 \ + || (CURRENT_FEATURE_BUNDLE == FEATURE_BUNDLE_CUSTOM && \ + FEATURE_IS_ENABLED_MASK(FEATURE_APOS_AS_NAME_SEP_BIT)) \ + ) + #define SAVEFEATUREBITS() SAVEI32(PL_compiling.cop_features) @@ -232,6 +242,9 @@ S_enable_feature_bundle(pTHX_ SV *ver) SV *comp_ver = sv_newmortal(); PL_hints = (PL_hints &~ HINT_FEATURE_MASK) | ( + (sv_setnv(comp_ver, 5.041), + vcmp(ver, upg_version(comp_ver, FALSE)) >= 0) + ? FEATURE_BUNDLE_541 : (sv_setnv(comp_ver, 5.039), vcmp(ver, upg_version(comp_ver, FALSE)) >= 0) ? FEATURE_BUNDLE_539 : @@ -287,6 +300,14 @@ S_magic_sethint_feature(pTHX_ SV *keysv, const char *keypv, STRLEN keylen, } return; + case 'a': + if (keylen == sizeof("feature_apos_as_name_sep")-1 + && memcmp(subf+1, "pos_as_name_sep", keylen - sizeof("feature_")) == 0) { + mask = FEATURE_APOS_AS_NAME_SEP_BIT; + break; + } + return; + case 'b': if (keylen == sizeof("feature_bareword_filehandles")-1 && memcmp(subf+1, "areword_filehandles", keylen - sizeof("feature_")) == 0) { @@ -445,6 +466,12 @@ struct perl_feature_bit { static const struct perl_feature_bit PL_feature_bits[] = { + { + /* feature apostrophe_as_package_separator */ + "feature_apos_as_name_sep", + STRLENs("feature_apos_as_name_sep"), + FEATURE_APOS_AS_NAME_SEP_BIT + }, { /* feature bareword_filehandles */ "feature_bareword_filehandles", diff --git a/lib/feature.pm b/lib/feature.pm index cf0531845d13..8d1c930ca542 100644 --- a/lib/feature.pm +++ b/lib/feature.pm @@ -4,43 +4,45 @@ # Any changes made here will be lost! package feature; -our $VERSION = '1.91'; +our $VERSION = '1.92'; our %feature = ( - fc => 'feature_fc', - isa => 'feature_isa', - say => 'feature_say', - try => 'feature_try', - class => 'feature_class', - defer => 'feature_defer', - state => 'feature_state', - bitwise => 'feature_bitwise', - indirect => 'feature_indirect', - evalbytes => 'feature_evalbytes', - signatures => 'feature_signatures', - current_sub => 'feature___SUB__', - module_true => 'feature_module_true', - refaliasing => 'feature_refaliasing', - postderef_qq => 'feature_postderef_qq', - unicode_eval => 'feature_unieval', - declared_refs => 'feature_myref', - unicode_strings => 'feature_unicode', - multidimensional => 'feature_multidimensional', - bareword_filehandles => 'feature_bareword_filehandles', - extra_paired_delimiters => 'feature_more_delims', + fc => 'feature_fc', + isa => 'feature_isa', + say => 'feature_say', + try => 'feature_try', + class => 'feature_class', + defer => 'feature_defer', + state => 'feature_state', + bitwise => 'feature_bitwise', + indirect => 'feature_indirect', + evalbytes => 'feature_evalbytes', + signatures => 'feature_signatures', + current_sub => 'feature___SUB__', + module_true => 'feature_module_true', + refaliasing => 'feature_refaliasing', + postderef_qq => 'feature_postderef_qq', + unicode_eval => 'feature_unieval', + declared_refs => 'feature_myref', + unicode_strings => 'feature_unicode', + multidimensional => 'feature_multidimensional', + bareword_filehandles => 'feature_bareword_filehandles', + extra_paired_delimiters => 'feature_more_delims', + apostrophe_as_package_separator => 'feature_apos_as_name_sep', ); our %feature_bundle = ( - "5.10" => [qw(bareword_filehandles indirect multidimensional say state)], - "5.11" => [qw(bareword_filehandles indirect multidimensional say state unicode_strings)], - "5.15" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings)], - "5.23" => [qw(bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings)], - "5.27" => [qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings)], - "5.35" => [qw(bareword_filehandles bitwise current_sub evalbytes fc isa postderef_qq say signatures state unicode_eval unicode_strings)], - "5.37" => [qw(bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures state unicode_eval unicode_strings)], - "5.39" => [qw(bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures state try unicode_eval unicode_strings)], - "all" => [qw(bareword_filehandles bitwise class current_sub declared_refs defer evalbytes extra_paired_delimiters fc indirect isa module_true multidimensional postderef_qq refaliasing say signatures state try unicode_eval unicode_strings)], - "default" => [qw(bareword_filehandles indirect multidimensional)], + "5.10" => [qw(apostrophe_as_package_separator bareword_filehandles indirect multidimensional say state)], + "5.11" => [qw(apostrophe_as_package_separator bareword_filehandles indirect multidimensional say state unicode_strings)], + "5.15" => [qw(apostrophe_as_package_separator bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings)], + "5.23" => [qw(apostrophe_as_package_separator bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings)], + "5.27" => [qw(apostrophe_as_package_separator bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings)], + "5.35" => [qw(apostrophe_as_package_separator bareword_filehandles bitwise current_sub evalbytes fc isa postderef_qq say signatures state unicode_eval unicode_strings)], + "5.37" => [qw(apostrophe_as_package_separator bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures state unicode_eval unicode_strings)], + "5.39" => [qw(apostrophe_as_package_separator bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures state try unicode_eval unicode_strings)], + "5.41" => [qw(bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures state try unicode_eval unicode_strings)], + "all" => [qw(apostrophe_as_package_separator bareword_filehandles bitwise class current_sub declared_refs defer evalbytes extra_paired_delimiters fc indirect isa module_true multidimensional postderef_qq refaliasing say signatures state try unicode_eval unicode_strings)], + "default" => [qw(apostrophe_as_package_separator bareword_filehandles indirect multidimensional)], ); $feature_bundle{"5.12"} = $feature_bundle{"5.11"}; @@ -66,8 +68,7 @@ $feature_bundle{"5.34"} = $feature_bundle{"5.27"}; $feature_bundle{"5.36"} = $feature_bundle{"5.35"}; $feature_bundle{"5.38"} = $feature_bundle{"5.37"}; $feature_bundle{"5.40"} = $feature_bundle{"5.39"}; -$feature_bundle{"5.41"} = $feature_bundle{"5.39"}; -$feature_bundle{"5.42"} = $feature_bundle{"5.39"}; +$feature_bundle{"5.42"} = $feature_bundle{"5.41"}; $feature_bundle{"5.9.5"} = $feature_bundle{"5.10"}; my %noops = ( postderef => 1, @@ -80,7 +81,7 @@ my %removed = ( our $hint_shift = 26; our $hint_mask = 0x3c000000; -our @hint_bundles = qw( default 5.10 5.11 5.15 5.23 5.27 5.35 5.37 5.39 ); +our @hint_bundles = qw( default 5.10 5.11 5.15 5.23 5.27 5.35 5.37 5.39 5.41 ); # This gets set (for now) in $^H as well as in %^H, # for runtime speed of the uc/lc/ucfirst/lcfirst functions. @@ -506,6 +507,18 @@ warn when you use the feature, unless you have explicitly disabled the warning: This feature enables the C block syntax and other associated keywords which implement the "new" object system, previously codenamed "Corinna". +=head2 The 'apostrophe_as_package_separator' feature + +This feature enables use C<'> (apostrophe) as an alternative to using +C<::> as a separate in package and other global names. + +This is enabled by default, but disabled from the 5.41 feature bundle +onwards. In previous versions it was enabled all the time. + +This only disables C<'> in symbols in your source code, the internal +conversion from C<'> to C<::>, including for symbolic references, is +always enabled. + =head1 FEATURE BUNDLES It's possible to load multiple features together, using @@ -520,71 +533,88 @@ The following feature bundles are available: --------- ----------------- :default indirect multidimensional bareword_filehandles + apostrophe_as_package_separator - :5.10 bareword_filehandles indirect + :5.10 apostrophe_as_package_separator + bareword_filehandles indirect multidimensional say state - :5.12 bareword_filehandles indirect + :5.12 apostrophe_as_package_separator + bareword_filehandles indirect multidimensional say state unicode_strings - :5.14 bareword_filehandles indirect + :5.14 apostrophe_as_package_separator + bareword_filehandles indirect multidimensional say state unicode_strings - :5.16 bareword_filehandles current_sub evalbytes + :5.16 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings - :5.18 bareword_filehandles current_sub evalbytes + :5.18 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings - :5.20 bareword_filehandles current_sub evalbytes + :5.20 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings - :5.22 bareword_filehandles current_sub evalbytes + :5.22 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional say state unicode_eval unicode_strings - :5.24 bareword_filehandles current_sub evalbytes + :5.24 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.26 bareword_filehandles current_sub evalbytes + :5.26 apostrophe_as_package_separator + bareword_filehandles current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.28 bareword_filehandles bitwise current_sub + :5.28 apostrophe_as_package_separator + bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.30 bareword_filehandles bitwise current_sub + :5.30 apostrophe_as_package_separator + bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.32 bareword_filehandles bitwise current_sub + :5.32 apostrophe_as_package_separator + bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.34 bareword_filehandles bitwise current_sub + :5.34 apostrophe_as_package_separator + bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state unicode_eval unicode_strings - :5.36 bareword_filehandles bitwise current_sub + :5.36 apostrophe_as_package_separator + bareword_filehandles bitwise current_sub evalbytes fc isa postderef_qq say signatures state unicode_eval unicode_strings - :5.38 bitwise current_sub evalbytes fc isa - module_true postderef_qq say signatures - state unicode_eval unicode_strings + :5.38 apostrophe_as_package_separator bitwise + current_sub evalbytes fc isa module_true + postderef_qq say signatures state + unicode_eval unicode_strings - :5.40 bitwise current_sub evalbytes fc isa - module_true postderef_qq say signatures - state try unicode_eval unicode_strings + :5.40 apostrophe_as_package_separator bitwise + current_sub evalbytes fc isa module_true + postderef_qq say signatures state try + unicode_eval unicode_strings :5.42 bitwise current_sub evalbytes fc isa module_true postderef_qq say signatures diff --git a/regen/feature.pl b/regen/feature.pl index 40f74f34d1f9..9ff19fbfca1a 100755 --- a/regen/feature.pl +++ b/regen/feature.pl @@ -45,6 +45,7 @@ BEGIN extra_paired_delimiters => 'more_delims', module_true => 'module_true', class => 'class', + apostrophe_as_package_separator => 'apos_as_name_sep', ); # NOTE: If a feature is ever enabled in a non-contiguous range of Perl @@ -54,7 +55,7 @@ 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 indirect multidimensional bareword_filehandles}; +use constant V5_9_5 => sort qw{say state indirect multidimensional bareword_filehandles apostrophe_as_package_separator}; 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} ); @@ -66,14 +67,17 @@ BEGIN use constant V5_37 => sort grep {; $_ ne 'bareword_filehandles' } +V5_35, qw{module_true}; use constant V5_39 => sort ( +V5_37, qw{try} ); -use constant V5_41 => sort ( +V5_39 ); +use constant V5_41 => sort + grep {; $_ ne 'apostrophe_as_package_separator' } + ( +V5_39 ); # # when updating features please also update the Pod entry for L # my %feature_bundle = ( all => [ sort keys %feature ], - default => [ qw{indirect multidimensional bareword_filehandles} ], + default => [ qw{indirect multidimensional bareword_filehandles + apostrophe_as_package_separator} ], # using 5.9.5 features bundle "5.9.5" => [ +V5_9_5 ], "5.10" => [ +V5_9_5 ], @@ -542,7 +546,7 @@ sub longest { __END__ package feature; -our $VERSION = '1.91'; +our $VERSION = '1.92'; FEATURES @@ -965,6 +969,18 @@ =head2 The 'class' feature This feature enables the C block syntax and other associated keywords which implement the "new" object system, previously codenamed "Corinna". +=head2 The 'apostrophe_as_package_separator' feature + +This feature enables use C<'> (apostrophe) as an alternative to using +C<::> as a separate in package and other global names. + +This is enabled by default, but disabled from the 5.41 feature bundle +onwards. In previous versions it was enabled all the time. + +This only disables C<'> in symbols in your source code, the internal +conversion from C<'> to C<::>, including for symbolic references, is +always enabled. + =head1 FEATURE BUNDLES It's possible to load multiple features together, using diff --git a/t/lib/feature/api b/t/lib/feature/api index 5ad798dd7aa5..1635e3e60207 100644 --- a/t/lib/feature/api +++ b/t/lib/feature/api @@ -17,10 +17,10 @@ BEGIN { print "bundle: ", feature::feature_bundle(0) // "undef", "\n"; } EXPECT -default: bareword_filehandles indirect multidimensional +default: apostrophe_as_package_separator bareword_filehandles indirect multidimensional unicode_strings is not enabled bundle: default -5.12: bareword_filehandles indirect multidimensional say state unicode_strings +5.12: apostrophe_as_package_separator bareword_filehandles indirect multidimensional say state unicode_strings unicode_strings is enabled bundle: 5.11 ######## @@ -40,9 +40,9 @@ BEGIN { print "bundle: ", feature::feature_bundle(0) // "undef", "\n"; } EXPECT -no feature indirect: bareword_filehandles multidimensional +no feature indirect: apostrophe_as_package_separator bareword_filehandles multidimensional indirect is not enabled bundle: undef -added unicode_strings: bareword_filehandles multidimensional unicode_strings +added unicode_strings: apostrophe_as_package_separator bareword_filehandles multidimensional unicode_strings unicode_strings is enabled bundle: undef From a4d969dc06b983d0a4d033b94dfea3e1f9c7bfbd Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Mon, 14 Oct 2024 10:31:45 +1100 Subject: [PATCH 6/9] feature apostrophe_as_package_separator implementation --- MANIFEST | 1 + embed.fnc | 9 +--- embed.h | 3 +- lib/overload.t | 2 +- pod/perldata.pod | 21 ++++----- proto.h | 7 +-- t/comp/package.t | 20 ++------- t/lib/croak/toke | 30 +++++++++++++ t/lib/feature/apos_as_pack_sep | 34 +++++++++++++++ t/lib/warnings/toke | 74 ++++++++++++++++++++++++++++++++ toke.c | 78 ++++++++++++++-------------------- 11 files changed, 188 insertions(+), 91 deletions(-) create mode 100644 t/lib/feature/apos_as_pack_sep diff --git a/MANIFEST b/MANIFEST index a9abbf69fce4..71ebd5b41286 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6105,6 +6105,7 @@ 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/Dies.pm For test case in op/require_errors.t t/lib/feature/api Test API for checking features enabled/disabled +t/lib/feature/apos_as_pack_sep Tests for enabling/disabling apostrophe_as_package_separator 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/embed.fnc b/embed.fnc index 8082864919d3..198073342d2e 100644 --- a/embed.fnc +++ b/embed.fnc @@ -3018,12 +3018,6 @@ EXpx |char * |scan_word |NN char *s \ |STRLEN destlen \ |int allow_package \ |NN STRLEN *slp -EXpx |char * |scan_word6 |NN char *s \ - |NN char *dest \ - |STRLEN destlen \ - |int allow_package \ - |NN STRLEN *slp \ - |bool warn_tick Cp |U32 |seed : Only used by perl.c/miniperl.c, but defined in caretx.c ep |void |set_caret_X @@ -5909,8 +5903,7 @@ S |void |parse_ident |NN char **s \ |NN char * const e \ |int allow_package \ |bool is_utf8 \ - |bool check_dollar \ - |bool tick_warn + |bool check_dollar S |int |pending_ident RS |char * |scan_const |NN char *start RS |char * |scan_formline |NN char *s diff --git a/embed.h b/embed.h index 458fa1aba984..973978756dc2 100644 --- a/embed.h +++ b/embed.h @@ -1629,7 +1629,7 @@ # define intuit_more(a,b) S_intuit_more(aTHX_ a,b) # define lop(a,b,c) S_lop(aTHX_ a,b,c) # define missingterm(a,b) S_missingterm(aTHX_ a,b) -# define parse_ident(a,b,c,d,e,f,g) S_parse_ident(aTHX_ a,b,c,d,e,f,g) +# define parse_ident(a,b,c,d,e,f) S_parse_ident(aTHX_ a,b,c,d,e,f) # define pending_ident() S_pending_ident(aTHX) # define scan_const(a) S_scan_const(aTHX_ a) # define scan_formline(a) S_scan_formline(aTHX_ a) @@ -1766,7 +1766,6 @@ # define report_uninit(a) Perl_report_uninit(aTHX_ a) # define scan_str(a,b,c,d,e) Perl_scan_str(aTHX_ a,b,c,d,e) # define scan_word(a,b,c,d,e) Perl_scan_word(aTHX_ a,b,c,d,e) -# define scan_word6(a,b,c,d,e,f) Perl_scan_word6(aTHX_ a,b,c,d,e,f) # define skipspace_flags(a,b) Perl_skipspace_flags(aTHX_ a,b) # define sv_magicext_mglob(a) Perl_sv_magicext_mglob(aTHX_ a) # define sv_only_taint_gmagic Perl_sv_only_taint_gmagic diff --git a/lib/overload.t b/lib/overload.t index 11062866b7d3..afe76d707cf8 100644 --- a/lib/overload.t +++ b/lib/overload.t @@ -2395,7 +2395,7 @@ is eval {"$a"}, overload::StrVal($a), { package mane; use overload q\""\ => "bear::strength"; - use overload bool => "bear'bouillon"; + use overload bool => "bear::bouillon"; } @bear::ISA = 'food'; sub food::strength { 'twine' } diff --git a/pod/perldata.pod b/pod/perldata.pod index 674386bb5625..1a6b842841de 100644 --- a/pod/perldata.pod +++ b/pod/perldata.pod @@ -136,22 +136,17 @@ generic characters, and identifiers should match That is, any word character in the ASCII range, as long as the first character is not a digit. -There are two package separators in Perl: A double colon (C<::>) and a single -quote (C<'>). Use of C<'> as the package separator is deprecated and will be -removed in Perl 5.40. Normal identifiers can start or end with a double -colon, and can contain several parts delimited by double colons. Single -quotes have similar rules, but with the exception that they are not legal at -the end of an identifier: That is, C<$'foo> and C<$foo'bar> are legal, but -C<$foo'bar'> is not. +There is one package separator in Perl: A double colon (C<::>). +Normal identifiers can start or end with a double colon, and can +contain several parts delimited by double colons. + +Previously you could use C<'> as a package separator, this was removed +in Perl 5.42. Additionally, if the identifier is preceded by a sigil -- that is, if the identifier is part of a variable name -- it may optionally be enclosed in braces. -While you can mix double colons with singles quotes, the quotes must come -after the colons: C<$::::'foo> and C<$foo::'bar> are legal, but C<$::'::foo> -and C<$foo'::bar> are not. - Put together, a grammar to match a basic identifier becomes / @@ -164,9 +159,9 @@ Put together, a grammar to match a basic identifier becomes ) ) (? - (?: :: )* '? + (?: :: )* (?&basic_identifier) - (?: (?= (?: :: )+ '? | (?: :: )* ' ) (?&normal_identifier) )? + (?: (?= :: ) (?&normal_identifier) )? (?: :: )* ) (? diff --git a/proto.h b/proto.h index 909cba273be3..64734e6d82e0 100644 --- a/proto.h +++ b/proto.h @@ -4191,11 +4191,6 @@ Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STR #define PERL_ARGS_ASSERT_SCAN_WORD \ assert(s); assert(dest); assert(slp) -PERL_CALLCONV char * -Perl_scan_word6(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp, bool warn_tick); -#define PERL_ARGS_ASSERT_SCAN_WORD6 \ - assert(s); assert(dest); assert(slp) - PERL_CALLCONV U32 Perl_seed(pTHX); #define PERL_ARGS_ASSERT_SEED @@ -9256,7 +9251,7 @@ S_new_constant(pTHX_ const char *s, STRLEN len, const char *key, STRLEN keylen, assert(key); assert(sv) STATIC void -S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, bool is_utf8, bool check_dollar, bool tick_warn); +S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, bool is_utf8, bool check_dollar); # define PERL_ARGS_ASSERT_PARSE_IDENT \ assert(s); assert(d); assert(e) diff --git a/t/comp/package.t b/t/comp/package.t index 7b19513bddf2..3f1d63702b5a 100644 --- a/t/comp/package.t +++ b/t/comp/package.t @@ -1,10 +1,5 @@ #!./perl -BEGIN { - @INC = qw(. ../lib); - chdir 't' if -d 't'; -} - print "1..14\n"; $blurfl = 123; @@ -18,14 +13,10 @@ $bar = 4; { package ABC; - no warnings qw(syntax deprecated); $blurfl = 5; $main'a = $'b; } -{ - no warnings qw(syntax deprecated); - $ABC'dyick = 6; -} +$ABC'dyick = 6; $xyz = 2; @@ -36,13 +27,10 @@ $ABC = join(':', sort(keys %ABC::)); if ('a' lt 'A') { print $xyz eq 'bar:main:new:xyz:ABC' ? "ok 1\n" : "not ok 1 '$xyz'\n"; } else { - print $xyz eq 'ABC:BEGIN:bar:main:new:xyz' ? "ok 1\n" : "not ok 1 '$xyz'\n"; -} -print $ABC eq 'BEGIN:blurfl:dyick' ? "ok 2\n" : "not ok 2 '$ABC'\n"; -{ - no warnings qw(syntax deprecated); - print $main'blurfl == 123 ? "ok 3\n" : "not ok 3\n"; + print $xyz eq 'ABC:bar:main:new:xyz' ? "ok 1\n" : "not ok 1 '$xyz'\n"; } +print $ABC eq 'blurfl:dyick' ? "ok 2\n" : "not ok 2 '$ABC'\n"; +print $main'blurfl == 123 ? "ok 3\n" : "not ok 3\n"; package ABC; diff --git a/t/lib/croak/toke b/t/lib/croak/toke index 190766d2cf47..ac766871e2d6 100644 --- a/t/lib/croak/toke +++ b/t/lib/croak/toke @@ -611,3 +611,33 @@ syntax error at - line 2, near "[ ==" (Might be a runaway multi-line // string starting on line 1) Execution of - aborted due to compilation errors. +######## +# NAME tick in names: initial character of sub name (reverted) +sub 'Hello'_he_said (_); +EXPECT +OPTIONS nonfatal +######## +# NAME tick in names: initial character of sub name (no feature) +no feature 'apostrophe_as_package_separator'; +sub 'Hello'_he_said (_); +EXPECT +Illegal declaration of anonymous subroutine at - line 2. +######## +# NAME tick in names: initial character of format name (reverted) + format 'one = +ok @<< - format 'foo still works +$test +. +EXPECT +OPTIONS nonfatal +######## +# NAME tick in names: initial character of format name (no feature_ +no feature 'apostrophe_as_package_separator'; + format 'one = +ok @<< - format 'foo still works +$test +. +EXPECT +syntax error at - line 3, near "ok @<< - format '" + (Might be a runaway multi-line '' string starting on line 2) +Execution of - aborted due to compilation errors. diff --git a/t/lib/feature/apos_as_pack_sep b/t/lib/feature/apos_as_pack_sep new file mode 100644 index 000000000000..657baaf481fc --- /dev/null +++ b/t/lib/feature/apos_as_pack_sep @@ -0,0 +1,34 @@ +Check apostrophe_as_package_separator feature + +__END__ +# NAME check default and 5.41 bundle +$foo'bar = 1; +use v5.41; +$foo'bar = 2; +EXPECT +OPTIONS fatal +Global symbol "$foo" requires explicit package name (did you forget to declare "my $foo"?) at - line 3. +Can't find string terminator "'" anywhere before EOF at - line 3. +######## +# NAME no feature apostrophe_as_package_separator +$foo'bar = 1; +no feature 'apostrophe_as_package_separator'; +$foo'bar = 2; +EXPECT +OPTIONS fatal +Can't find string terminator "'" anywhere before EOF at - line 3. +######## +# NAME use feature apostrophe_as_package_separator +use v5.41; +use feature 'apostrophe_as_package_separator'; +$foo'bar = 2; +$foo'bar = 3; # suppress used only once +EXPECT +######## +# NAME ' in symbolic refs always works and is treated as :: +my $x = "foo'bar"; +no feature 'apostrophe_as_package_separator'; +$$x = "Hello\n"; +print $foo::bar; +EXPECT +Hello diff --git a/t/lib/warnings/toke b/t/lib/warnings/toke index 054a740bd397..6938174544fd 100644 --- a/t/lib/warnings/toke +++ b/t/lib/warnings/toke @@ -407,6 +407,80 @@ no warnings 'syntax' ; sort ("") EXPECT +######## +@foo::bar = 1..3; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +use warnings 'syntax'; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +no warnings 'syntax', 'deprecated' ; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +# ' in names no longer deprecated, ensure we don't warn +EXPECT +######## +use warnings 'syntax'; use utf8; +@fooл::barл = 1..3; +() = "$fooл'barл"; +() = "@fooл'barл"; +() = "$#fooл'barл"; +no warnings 'syntax', 'deprecated' ; +() = "$fooл'barл"; +() = "@fooл'barл"; +() = "$#fooл'barл"; +# ' in names no longer deprecated, ensure we don't warn +EXPECT +######## +# NAME deprecation of ' in names reverted +sub foo'bar { 1 } +$a'b = 1; +@a'c = (); +%a'd = (); +package a'e; +# ' in names no longer deprecated, ensure we don't warn +EXPECT +######## +# NAME ' no longer is part of the symbol character set (reverted) +# previously these would parse like: +# "${foo'bar}", but they did parse like "${foo}'bar" +# but now they parse in names again +@foo::bar = 1..3; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +use warnings 'syntax'; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +no warnings 'syntax', 'deprecated' ; +() = "$foo'bar"; +() = "@foo'bar"; +() = "$#foo'bar"; +EXPECT +######## +# similar to the test above in that the parsing has changed +use warnings 'syntax'; use utf8; +@fooл::barл = 1..3; +() = "$fooл'barл"; +() = "@fooл'barл"; +() = "$#fooл'barл"; +no warnings 'syntax', 'deprecated' ; +() = "$fooл'barл"; +() = "@fooл'barл"; +() = "$#fooл'barл"; +EXPECT +######## +# NAME deprecation of ' in names (reverted) +sub foo'bar { 1 } +$a'b = 1; +@a'c = (); +%a'd = (); +package a'e; +EXPECT ######## # toke.c use warnings 'ambiguous' ; diff --git a/toke.c b/toke.c index 54c688d7db69..22ba91f6cffb 100644 --- a/toke.c +++ b/toke.c @@ -2308,7 +2308,7 @@ S_force_word(pTHX_ char *start, int token, int check_keyword, int allow_pack) if ( isIDFIRST_lazy_if_safe(s, PL_bufend, UTF) || (allow_pack && *s == ':' && s[1] == ':') ) { - s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, allow_pack, &len, allow_pack); + s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, allow_pack, &len); if (check_keyword) { char *s2 = PL_tokenbuf; STRLEN len2 = len; @@ -4847,7 +4847,7 @@ S_intuit_method(pTHX_ char *start, SV *ioname, CV *cv) return *s == '(' ? METHCALL : METHCALL0; } - s = scan_word6(s, tmpbuf, sizeof tmpbuf, TRUE, &len, FALSE); + s = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len); /* start is the beginning of the possible filehandle/object, * and s is the end of it * tmpbuf is a copy of it (but with single quotes as double colons) @@ -5296,7 +5296,7 @@ yyl_sigvar(pTHX_ char *s) /* read var name, including sigil, into PL_tokenbuf */ PL_tokenbuf[0] = sigil; parse_ident(&s, &dest, dest + sizeof(PL_tokenbuf) - 1, - 0, cBOOL(UTF), FALSE, FALSE); + 0, cBOOL(UTF), FALSE); *dest = '\0'; assert(PL_tokenbuf[1]); /* we have a variable name */ } @@ -5519,7 +5519,7 @@ yyl_dollar(pTHX_ char *s) char tmpbuf[sizeof PL_tokenbuf]; int t2; STRLEN len; - scan_word6(s, tmpbuf, sizeof tmpbuf, TRUE, &len, FALSE); + scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len); if ((t2 = keyword(tmpbuf, len, 0))) { /* binary operators exclude handle interpretations */ switch (t2) { @@ -5585,13 +5585,12 @@ yyl_sub(pTHX_ char *s, const int key) PL_parser->sig_seen = FALSE; if ( isIDFIRST_lazy_if_safe(s, PL_bufend, UTF) - || *s == '\'' + || (*s == '\'' && FEATURE_APOS_AS_NAME_SEP_IS_ENABLED) || (*s == ':' && s[1] == ':')) { PL_expect = XATTRBLOCK; - d = scan_word6(s, tmpbuf, sizeof PL_tokenbuf - 1, TRUE, - &len, TRUE); + d = scan_word(s, tmpbuf, sizeof PL_tokenbuf - 1, TRUE, &len); if (key == KEY_format) format_name = S_newSV_maybe_utf8(aTHX_ s, d - s); *PL_tokenbuf = '&'; @@ -6183,7 +6182,7 @@ yyl_colon(pTHX_ char *s) I32 tmp; SV *sv; STRLEN len; - char *d = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); + char *d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len, 0))) { if (tmp < 0) tmp = -tmp; switch (tmp) { @@ -6362,8 +6361,8 @@ yyl_leftcurly(pTHX_ char *s, const U8 formbrack) } if (d < PL_bufend && isIDFIRST_lazy_if_safe(d, PL_bufend, UTF)) { STRLEN len; - d = scan_word6(d, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, - FALSE, &len, FALSE); + d = scan_word(d, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, + FALSE, &len); while (d < PL_bufend && SPACE_OR_TAB(*d)) d++; if (*d == '}') { @@ -7168,7 +7167,7 @@ yyl_foreach(pTHX_ char *s) /* skip optional package name, as in "for my abc $x (..)" */ if (UNLIKELY(isIDFIRST_lazy_if_safe(p, PL_bufend, UTF))) { STRLEN len; - p = scan_word6(p, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len, TRUE); + p = scan_word(p, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len); p = skipspace(p); paren_is_valid = FALSE; } @@ -7197,8 +7196,8 @@ yyl_do(pTHX_ char *s, I32 orig_keyword) char *d; STRLEN len; *PL_tokenbuf = '&'; - d = scan_word6(s, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, - 1, &len, TRUE); + d = scan_word(s, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, + 1, &len); if (len && memNEs(PL_tokenbuf+1, len, "CORE") && !keyword(PL_tokenbuf + 1, len, 0)) { SSize_t off = s-SvPVX(PL_linestr); @@ -7233,7 +7232,7 @@ yyl_my(pTHX_ char *s, I32 my) s = skipspace(s); if (isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) { STRLEN len; - s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len, TRUE); + s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len); if (memEQs(PL_tokenbuf, len, "sub")) return yyl_sub(aTHX_ s, my); PL_in_my_stash = find_in_my_stash(PL_tokenbuf, len); @@ -7703,10 +7702,11 @@ yyl_just_a_word(pTHX_ char *s, STRLEN len, I32 orig_keyword, struct code c) /* Get the rest if it looks like a package qualifier */ - if (*s == '\'' || (*s == ':' && s[1] == ':')) { + if ((*s == '\'' && FEATURE_APOS_AS_NAME_SEP_IS_ENABLED) + || (*s == ':' && s[1] == ':')) { STRLEN morelen; - s = scan_word6(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len, - TRUE, &morelen, TRUE); + s = scan_word(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len, + TRUE, &morelen); if (no_op_error) { S_warn_expect_operator(aTHX_ "Bareword",s,FALSE); no_op_error = FALSE; @@ -8436,7 +8436,7 @@ yyl_word_or_keyword(pTHX_ char *s, STRLEN len, I32 key, I32 orig_keyword, struct s = skipspace(s); if (isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) { const char *t; - char *d = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); + char *d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); for (t=d; isSPACE(*t);) t++; if ( *t && memCHRs("|&*+-=!?:.", *t) && ckWARN_d(WARN_PRECEDENCE) @@ -8864,9 +8864,10 @@ yyl_key_core(pTHX_ char *s, STRLEN len, struct code c) STRLEN olen = len; char *d = s; s += 2; - s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); + s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); if ((*s == ':' && s[1] == ':') - || (!(key = keyword(PL_tokenbuf, len, 1)) && *s == '\'')) + || (!(key = keyword(PL_tokenbuf, len, 1)) && *s == '\'' && + FEATURE_APOS_AS_NAME_SEP_IS_ENABLED)) { Copy(PL_bufptr, PL_tokenbuf, olen, char); return yyl_just_a_word(aTHX_ d, olen, 0, c); @@ -8943,7 +8944,7 @@ yyl_keylookup(pTHX_ char *s, GV *gv) c.gv = gv; PL_bufptr = s; - s = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len, FALSE); + s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); /* Some keywords can be followed by any delimiter, including ':' */ anydelim = word_takes_any_delimiter(PL_tokenbuf, len); @@ -10273,10 +10274,8 @@ S_new_constant(pTHX_ const char *s, STRLEN len, const char *key, STRLEN keylen, PERL_STATIC_INLINE void S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, - bool is_utf8, bool check_dollar, bool tick_warn) + bool is_utf8, bool check_dollar) { - int saw_tick = 0; - const char *olds = *s; PERL_ARGS_ASSERT_PARSE_IDENT; while (*s < PL_bufend) { @@ -10305,12 +10304,12 @@ S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, } else if ( allow_package && **s == '\'' + && FEATURE_APOS_AS_NAME_SEP_IS_ENABLED && isIDFIRST_lazy_if_safe((*s)+1, PL_bufend, is_utf8)) { *(*d)++ = ':'; *(*d)++ = ':'; (*s)++; - saw_tick++; } else if (allow_package && **s == ':' && (*s)[1] == ':' /* Disallow things like Foo::$bar. For the curious, this is @@ -10327,33 +10326,21 @@ S_parse_ident(pTHX_ char **s, char **d, char * const e, int allow_package, return; } -/* Returns a NUL terminated string, with the length of the string written to - *slp - - scan_word6() may be removed once ' in names is removed. - */ char * -Perl_scan_word6(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp, bool warn_tick) +Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp) { + PERL_ARGS_ASSERT_SCAN_WORD; + char *d = dest; char * const e = d + destlen - 3; /* two-character token, ending NUL */ bool is_utf8 = cBOOL(UTF); - PERL_ARGS_ASSERT_SCAN_WORD6; - - parse_ident(&s, &d, e, allow_package, is_utf8, TRUE, warn_tick); + parse_ident(&s, &d, e, allow_package, is_utf8, TRUE); *d = '\0'; *slp = d - dest; return s; } -char * -Perl_scan_word(pTHX_ char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp) -{ - PERL_ARGS_ASSERT_SCAN_WORD; - return scan_word6(s, dest, destlen, allow_package, slp, FALSE); -} - /* scan s and extract an identifier ($var) from it if possible * into dest. * XXX: This function has subtle implications on parsing, and @@ -10389,7 +10376,7 @@ S_scan_ident(pTHX_ char *s, char *dest, STRLEN destlen, I32 ck_uni) Perl_croak(aTHX_ ident_var_zero_multi_digit); } else { /* See if it is a "normal" identifier */ - parse_ident(&s, &d, e, 1, is_utf8, FALSE, TRUE); + parse_ident(&s, &d, e, 1, is_utf8, FALSE); } *d = '\0'; d = dest; @@ -10514,7 +10501,7 @@ S_scan_ident(pTHX_ char *s, char *dest, STRLEN destlen, I32 ck_uni) (the later check for } being at the expected point will trap cases where this doesn't pan out.) */ d += is_utf8 ? UTF8SKIP(d) : 1; - parse_ident(&s, &d, e, 1, is_utf8, TRUE, TRUE); + parse_ident(&s, &d, e, 1, is_utf8, TRUE); *d = '\0'; } else { /* caret word: ${^Foo} ${^CAPTURE[0]} */ @@ -11461,7 +11448,8 @@ S_scan_inputsymbol(pTHX_ char *start) if (*d == '$' && d[1]) d++; /* allow or */ - while (isWORDCHAR_lazy_if_safe(d, e, UTF) || *d == '\'' || *d == ':') { + while (isWORDCHAR_lazy_if_safe(d, e, UTF) || *d == ':' + || (*d == '\'' && FEATURE_APOS_AS_NAME_SEP_IS_ENABLED)) { d += UTF ? UTF8SKIP(d) : 1; } @@ -13806,7 +13794,7 @@ Perl_parse_label(pTHX_ U32 flags) t = s = PL_bufptr; if (!isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)) goto no_label; - t = scan_word6(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &wlen, FALSE); + t = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &wlen); if (word_takes_any_delimiter(s, wlen)) goto no_label; bufptr_pos = s - SvPVX(PL_linestr); From 79164e3ce3173e3865739b3453162ac0fae318ac Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 15 Oct 2024 10:28:11 +1100 Subject: [PATCH 7/9] parent: adjust for ' in names reinstatement --- cpan/parent/t/compile-time-file.t | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cpan/parent/t/compile-time-file.t b/cpan/parent/t/compile-time-file.t index bff886155297..0fc2ad9d4d75 100644 --- a/cpan/parent/t/compile-time-file.t +++ b/cpan/parent/t/compile-time-file.t @@ -24,7 +24,7 @@ use lib 't/lib'; { package Child3; - use parent "Dummy'Outside"; + use if $] != 5.041_003, parent => "Dummy'Outside"; } my $obj = {}; @@ -39,9 +39,12 @@ isa_ok $obj, 'Dummy::InlineChild'; can_ok $obj, 'exclaim'; is $obj->exclaim, "I CAN FROM Dummy::InlineChild", 'Inheritance is set up correctly for inlined classes'; -$obj = {}; -bless $obj, 'Child3'; -isa_ok $obj, 'Dummy::Outside'; -can_ok $obj, 'exclaim'; -is $obj->exclaim, "I CAN FROM Dummy::Outside", "Inheritance is set up correctly for classes inherited from via '"; - +SKIP: +{ + skip "No ' in names in 5.041_003", 3 if $] == 5.041_003; + $obj = {}; + bless $obj, 'Child3'; + isa_ok $obj, 'Dummy::Outside'; + can_ok $obj, 'exclaim'; + is $obj->exclaim, "I CAN FROM Dummy::Outside", "Inheritance is set up correctly for classes inherited from via '"; +} From 8e34742b3d8f3906a0448d10b6ae7ec59ad3831c Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Wed, 16 Oct 2024 10:41:00 +1100 Subject: [PATCH 8/9] Scalar-List-Utils: ' valid in names by default again --- cpan/Scalar-List-Utils/t/exotic_names.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpan/Scalar-List-Utils/t/exotic_names.t b/cpan/Scalar-List-Utils/t/exotic_names.t index e37418d7ed0e..395a817ef8ee 100644 --- a/cpan/Scalar-List-Utils/t/exotic_names.t +++ b/cpan/Scalar-List-Utils/t/exotic_names.t @@ -45,7 +45,7 @@ sub caller3_ok { ), ); - $expected =~ s/'/::/g; + $expected =~ s/'/::/g if $] < 5.037009 || $] >= 5.041_004; # this is apparently how things worked before 5.16 utf8::encode($expected) if $] < 5.016 and $ord > 255; @@ -72,7 +72,7 @@ my @ordinal = ( ($] >= 5.014 ? ( 0 ) : ()), 1 .. 38, # single quote ' separators are deprecated in 5.37.9 - ($] < 5.037009 ? ( 39 ) : ()), + ($] < 5.037009 || $] >= 5.041_004 ? ( 39 ) : ()), 40 .. 255, # Unicode in 5.6 is not sane (crashes etc) ($] >= 5.008 ? ( @@ -85,7 +85,7 @@ my @ordinal = ( my $legal_ident_char = join('', "A-Z_a-z0-9", - q['], + ($] < 5.037009 || $] >= 5.041_004 ? q['] : ()), ($] > 5.008 ? ( map chr, 0x100, 0x498 ) : ()), From 343ee03aa568481286780614ee3f0cfb93c1e11e Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Thu, 31 Oct 2024 15:04:46 +1100 Subject: [PATCH 9/9] perlmod: change the ' deprecation note to mention the feature --- pod/perlmod.pod | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pod/perlmod.pod b/pod/perlmod.pod index 117142f2e94f..e6f396f18f2a 100644 --- a/pod/perlmod.pod +++ b/pod/perlmod.pod @@ -81,8 +81,12 @@ the $s variable in package C, which is probably not what you meant. Use braces to disambiguate, as in C<"This is ${owner}'s house">. X<::> X<'> -Using C<'> as a package separator is deprecated and will be removed in -Perl 5.40. + +Use of C<'> as a package delimiter can be disabled with: + + no feature 'apostrophe_as_package_separator'; + +and is also disabled by C or later. Packages may themselves contain package separators, as in C<$OUTER::INNER::var>. This implies nothing about the order of