Skip Menu |
Report information
Id: 132013
Status: open
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: eda [at] waniasset.com
Cc:
AdminCc:

Operating System: Linux
PatchStatus: (no value)
Severity: Wishlist
Type: core
Perl Version: 5.22.2
Fixed In: (no value)

Attachments
0001-perl-132013-implement-strict-punctuation.patch



From: <eda [...] waniasset.com>
Subject: 'no formats'
Date: Fri, 1 Sep 2017 16:50:37 +0100
To: <perlbug [...] perl.org>
CC: <root [...] wcl-linux04.wcl.local>
Download (untitled) / with headers
text/plain 7.3k
This is a bug report for perl from eda@waniasset.com, generated with the help of perlbug 1.40 running under perl 5.22.2. ----------------------------------------------------------------- [Please describe your issue here] It would be useful to have no formats; to turn off, at compile time, features related to formats (until re-enabled with 'use formats'). This is useful because of the fair number of format-only special variables such as $- and $=, whose existence tends to make it harder to detect typos in code. If the programmer can declare that formats aren't being used, perl can give a helpful message on seeing these. [Please do not change anything below this line] ----------------------------------------------------------------- --- Flags: category=core severity=wishlist --- Site configuration information for perl 5.22.2: Configured by Red Hat, Inc. at Fri Nov 4 14:35:02 UTC 2016. Summary of my perl5 (revision 5 version 22 subversion 2) configuration: Platform: osname=linux, osvers=4.7.9-200.fc24.x86_64, archname=x86_64-linux-thread-multi uname='linux buildvm-12.phx2.fedoraproject.org 4.7.9-200.fc24.x86_64 #1 smp thu oct 20 14:26:16 utc 2016 x86_64 x86_64 x86_64 gnulinux ' config_args='-des -Doptimize=none -Dccflags=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -Dldflags=-Wl,-z,relro -Dccdlflags=-Wl,--enable-new-dtags -Wl,-z,relro -Dlddlflags=-shared -Wl,-z,relro -Dshrpdir=/usr/lib64 -DDEBUGGING=-g -Dversion=5.22.2 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dprefix=/usr -Dvendorprefix=/usr -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl5 -Dsitearch=/usr/local/lib64/perl5 -Dprivlib=/usr/share/perl5 -Dvendorlib=/usr/share/perl5/vendor_perl -Darchlib=/usr/lib64/perl5 -Dvendorarch=/usr/lib64/perl5/vendor_perl -Darchname=x86_64-linux-thread-multi -Dlibpth=/usr/local/lib64 /lib64 /usr/lib64 -Duseshrplib -Dusethreads -Duseithreads -Dusedtrace=/usr/bin/dtrace -Duselargefiles -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl=n -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dd_gethostent_r_proto -Ud_endhostent_r_proto -Ud_sethostent_r_proto -Ud_endprotoent_r_proto -Ud_setprotoent_r_proto -Ud_endservent_r_proto -Ud_setservent_r_proto -Dscriptdir=/usr/bin -Dusesitecustomize' hint=recommended, useposix=true, d_sigaction=define useithreads=define, usemultiplicity=define use64bitint=define, use64bitall=define, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize=' -g', cppflags='-D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fwrapv -fno-strict-aliasing -I/usr/local/include' ccversion='', gccversion='5.3.1 20160406 (Red Hat 5.3.1-6)', gccosandvers='' intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3 ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='gcc', ldflags ='-Wl,-z,relro -fstack-protector-strong -L/usr/local/lib' libpth=/usr/local/lib64 /lib64 /usr/lib64 /usr/local/lib /usr/lib /lib/../lib64 /usr/lib/../lib64 /lib libs=-lpthread -lresolv -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat perllibs=-lpthread -lresolv -lnsl -ldl -lm -lcrypt -lutil -lc libc=libc-2.22.so, so=so, useshrplib=true, libperl=libperl.so gnulibc_version='2.22' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,--enable-new-dtags -Wl,-z,relro ' cccdlflags='-fPIC', lddlflags='-shared -Wl,-z,relro -L/usr/local/lib -fstack-protector-strong' Locally applied patches: Fedora Patch1: Removes date check, Fedora/RHEL specific Fedora Patch3: support for libdir64 Fedora Patch4: use libresolv instead of libbind Fedora Patch5: USE_MM_LD_RUN_PATH Fedora Patch6: Skip hostname tests, due to builders not being network capable Fedora Patch7: Dont run one io test due to random builder failures Fedora Patch15: Define SONAME for libperl.so Fedora Patch16: Install libperl.so to -Dshrpdir value Fedora Patch22: Document Math::BigInt::CalcEmu requires Math::BigInt (CPAN RT#85015) Fedora Patch26: Make *DBM_File desctructors thread-safe (RT#61912) Fedora Patch27: Make PadlistNAMES() lvalue again (CPAN RT#101063) Fedora Patch28: Make magic vtable writable as a work-around for Coro (CPAN RT#101063) Fedora Patch29: Fix duplicating PerlIO::encoding when spawning threads (RT#31923) Fedora Patch30: Do not let XSLoader load relative paths (CVE-2016-6185) Fedora Patch31: Avoid loading optional modules from default . (CVE-2016-1238) Fedora Patch32: Fix a crash in lexical scope warnings (RT#128597) Fedora Patch33: Do not mangle errno from failed socket calls (RT#128316) Fedora Patch34: Fix crash in "evalbytes S" (RT#129196) Fedora Patch35: Fix crash in "evalbytes S" (RT#129196) Fedora Patch36: Fix crash in "evalbytes S" (RT#129196) Fedora Patch37: Fix crash in splice (RT#129164, RT#129166, RT#129167) Fedora Patch38: Fix string overrun in Perl_gv_fetchmethod_pvn_flags (RT#129267) Fedora Patch39: Fix string overrun in Perl_gv_fetchmethod_pvn_flags (RT#129267) Fedora Patch40: Fix string overrun in Perl_gv_fetchmethod_pvn_flags (RT#129267) Fedora Patch41: Fix string overrun in Perl_gv_fetchmethod_pvn_flags (RT#129267) Fedora Patch42: Fix string overrun in Perl_gv_fetchmethod_pvn_flags (RT#129267) Fedora Patch43: Fix crash when matching UTF-8 string with non-UTF-8 substrings (RT#129350) Fedora Patch44: Fix parsing perl options in shell bang line (RT#129336) Fedora Patch45: Fix firstchar bitmap under UTF-8 with prefix optimization (RT#129950) Fedora Patch46: Avoid infinite loop in h2xs tool if enum and type have the same name (RT130001) Fedora Patch47: Fix stack handling when calling chdir without an argument (RT#129130) Fedora Patch200: Link XS modules to libperl.so with EU::CBuilder on Linux Fedora Patch201: Link XS modules to libperl.so with EU::MM on Linux --- @INC for perl 5.22.2: /home/eda/lib64/perl5/ /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 --- Environment for perl 5.22.2: HOME=/home/eda LANG=en_GB.UTF-8 LANGUAGE (unset) LC_COLLATE=C LC_CTYPE=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8 LC_MONETARY=en_GB.UTF-8 LC_NUMERIC=en_GB.UTF-8 LC_TIME=en_GB.UTF-8 LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/home/eda/bin:/home/eda/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/sbin:/home/eda/.local/bin:/home/eda/bin:/sbin:/usr/sbin PERL5LIB=/home/eda/lib64/perl5/ PERL_BADLANG (unset) SHELL=/bin/bash
To: perl5-porters [...] perl.org
Date: Fri, 1 Sep 2017 19:07:16 +0100
Subject: Re: [perl #132013] 'no formats'
From: Zefram <zefram [...] fysh.org>
Ed Avis wrote: Show quoted text
>This is useful because of the fair number of format-only special >variables such as $- and $=, whose existence tends to make it harder >to detect typos in code.
I don't think this justifies a core feature, at least not yet. It would be possible for a CPAN module to disable the use of those magic variables, so that would seem to satisfy your use case. (In fact my module IO::ExplicitHandle does disable a bunch of them, along with the implicit-handle form of some ops.) If such a stricture module becomes very popular then we might consider implementing it in the core in some form. Thinking in terms of a stricture that disables magic variables, taking out only the format-related ones doesn't seem the most useful approach. Nor does it seem useful to disable other aspects of formats. It would probably be better for a stricture to disable *all* of the punctuation-named variables, with the exception of ones listed in the "use" invocation. Effectively requiring declaration of each magic variable before use. So you'd say something like use strict::punctuation qw(except $_ $@); -zefram
From: Andy Lester <andy [...] petdance.com>
Subject: Re: [perl #132013] 'no formats'
CC: perl5-porters [...] perl.org
Date: Fri, 1 Sep 2017 13:28:45 -0500
To: Zefram <zefram [...] fysh.org>
Download (untitled) / with headers
text/plain 440b

Show quoted text
On Sep 1, 2017, at 1:07 PM, Zefram <zefram@fysh.org> wrote:

This is useful because of the fair number of format-only special
variables such as $- and $=, whose existence tends to make it harder
to detect typos in code.

Perl::Critic already has a policy that forbids using formats. 


I could see expanding that to include any format-only variables.
CC: Perl5 Porteros <perl5-porters [...] perl.org>, Zefram <zefram [...] fysh.org>
Date: Fri, 1 Sep 2017 15:40:45 -0500
To: Sam Kington <sam [...] illuminated.co.uk>
From: Andy Lester <andy [...] petdance.com>
Subject: Re: [perl #132013] 'no formats'
Download (untitled) / with headers
text/plain 564b

Show quoted text
Perl::Critic requires a heroic amount of tweaking even to be useful at the minimal level, though. Something that says “I don’t even understand formats, let alone use them” might be useful to people who don’t have the patience to wrangle Perl::Critic.

I wasn’t arguing against the idea.  I’d love to see it.  I was just pointing out an alternative solution if the original idea doesn’t get implemented.  



Subject: Re: [perl #132013] 'no formats'
From: Abigail <abigail [...] abigail.be>
CC: perl5-porters [...] perl.org, Zefram <zefram [...] fysh.org>, Andy Lester <andy [...] petdance.com>
Date: Sat, 2 Sep 2017 01:58:24 +0200
To: Sam Kington <sam [...] illuminated.co.uk>
Download (untitled) / with headers
text/plain 1.5k
On Fri, Sep 01, 2017 at 10:32:55PM +0200, Sam Kington wrote: Show quoted text
> >>> This is useful because of the fair number of format-only special > >>> variables such as $- and $=, whose existence tends to make it harder > >>> to detect typos in code.
> > > > Perl::Critic already has a policy that forbids using formats. > > > > https://metacpan.org/pod/Perl::Critic::Policy::Miscellanea::ProhibitFormats > > > > I could see expanding that to include any format-only variables.
> > Perl::Critic requires a heroic amount of tweaking even to be useful at the minimal level, though. Something that says “I don’t even understand formats, let alone use them” might be useful to people who don’t have the patience to wrangle Perl::Critic. > > An interesting related question would be: what other parts of Perl are there that could be potentially made optional? Is e.g. dbmopen still core? There’s no reason why “use feature ‘foo’” should be reserved for something that’s new to that particular version of Perl; we could easily say “if you still want to use formats, which aren’t deprecated but aren’t that commonly-used, say use feature ‘formats’” in one version of Perl, and emit warnings if people don’t explicitly use the feature. >
I don't see the win of requiring people to use "use feature 'foo'" for a feature that's currently in core, and which you don't want to get rid of. There isn't less functionality to support (after all, we're keeping said features), in fact, there will be more (because now we live in a world where a feature can be on or off). Abigail
CC: Sam Kington <sam [...] illuminated.co.uk>, Perl5 Porters <perl5-porters [...] perl.org>, Zefram <zefram [...] fysh.org>, Andy Lester <andy [...] petdance.com>
Date: Sat, 2 Sep 2017 13:50:41 +0200
Subject: Re: [perl #132013] 'no formats'
From: Leon Timmermans <fawaka [...] gmail.com>
To: Abigail <abigail [...] abigail.be>
Download (untitled) / with headers
text/plain 422b
On Sat, Sep 2, 2017 at 1:58 AM, Abigail <abigail@abigail.be> wrote:
Show quoted text
I don't see the win of requiring people to use "use feature 'foo'" for a
feature that's currently in core, and which you don't want to get rid of.

There isn't less functionality to support (after all, we're keeping said
features), in fact, there will be more (because now we live in a world
where a feature can be on or off).

Agreed

Leon
Date: Sat, 2 Sep 2017 15:10:30 +0200
To: Sam Kington <sam [...] illuminated.co.uk>
CC: perl5-porters [...] perl.org, Zefram <zefram [...] fysh.org>, Andy Lester <andy [...] petdance.com>
Subject: Re: [perl #132013] 'no formats'
From: "H.Merijn Brand" <h.m.brand [...] xs4all.nl>
Download (untitled) / with headers
text/plain 2.8k
On Fri, 1 Sep 2017 22:32:55 +0200, Sam Kington <sam@illuminated.co.uk> wrote: Show quoted text
> > Perl::Critic already has a policy that forbids using formats. > > > > https://metacpan.org/pod/Perl::Critic::Policy::Miscellanea::ProhibitFormats > > > > I could see expanding that to include any format-only variables.
> > Perl::Critic requires a heroic amount of tweaking even to be useful > at the minimal level, though. Something that says “I don’t even > understand formats, let alone use them” might be useful to people who > don’t have the patience to wrangle Perl::Critic.
Where the heroic effort is done by volunteers that care for that specific issue. Choosing to have that option on or of is easy in your ~/.perlcriticrc $ grep -i format ~/.perlcriticrc [-Miscellanea::ProhibitFormats] [-RegularExpressions::RequireExtendedFormatting] So, I have this module installed, but - being a user of formats - I disabled it. Look at that like having the feature to use formats on by default. Show quoted text
> An interesting related question would be: what other parts of Perl > are there that could be potentially made optional? Is e.g. dbmopen > still core?
Interesting question, but what would be the gain. As Abigail already noted, there is not a lot. People would then have to explicitly tell the scope to disable it. If one does not know about it or does not use it, why disable it? It is like telling "I won't eat glass". Not that I ever do, but it is possible. I embrace the idea that if you want to protect yourself from eating glass, you just shouldn't. If you are afraid that some part of your code might accidentally use features you don't want to use (because you made a typo), Perl::Critic is *THE* tool to use. There simply are too many obscure/unknown/powerful/whatever features in the perl core to have "no feature" pragma's for. Show quoted text
> There’s no reason why “use feature ‘foo’” should be reserved for > something that’s new to that particular version of Perl; we could > easily say “if you still want to use formats, which aren’t deprecated
you assume formats will be deprecated? Why? Show quoted text
> but aren’t that commonly-used,
You don't know DarkPAN. What is "commonly used"? I *never* used threads in any of my perl scripts. Is that a reason to call it "not commonly used"? Did you ever use long doubles or quad doubles? Quad doubles are relatively new, so I'd expect them to not being commonly used, but that is no reason to disable that or get rid of it. Does having a useful feature like formats hinder your development? Show quoted text
> say use feature ‘formats’” in one version of Perl, and emit warnings > if people don’t explicitly use the feature. > > Sam
-- H.Merijn Brand http://tux.nl Perl Monger http://amsterdam.pm.org/ using perl5.00307 .. 5.27 porting perl5 on HP-UX, AIX, and openSUSE http://mirrors.develooper.com/hpux/ http://www.test-smoke.org/ http://qa.perl.org http://www.goldmark.org/jeff/stupid-disclaimers/
Download (untitled)
application/pgp-signature 473b

Message body not shown because it is not plain text.

To: perl5-porters [...] perl.org
CC: Zefram <zefram [...] fysh.org>, Andy Lester <andy [...] petdance.com>
Date: Fri, 1 Sep 2017 22:32:55 +0200
From: Sam Kington <sam [...] illuminated.co.uk>
Subject: Re: [perl #132013] 'no formats'
Download (untitled) / with headers
text/plain 1.1k
Show quoted text
>>> This is useful because of the fair number of format-only special >>> variables such as $- and $=, whose existence tends to make it harder >>> to detect typos in code.
> > Perl::Critic already has a policy that forbids using formats. > > https://metacpan.org/pod/Perl::Critic::Policy::Miscellanea::ProhibitFormats > > I could see expanding that to include any format-only variables.
Perl::Critic requires a heroic amount of tweaking even to be useful at the minimal level, though. Something that says “I don’t even understand formats, let alone use them” might be useful to people who don’t have the patience to wrangle Perl::Critic. An interesting related question would be: what other parts of Perl are there that could be potentially made optional? Is e.g. dbmopen still core? There’s no reason why “use feature ‘foo’” should be reserved for something that’s new to that particular version of Perl; we could easily say “if you still want to use formats, which aren’t deprecated but aren’t that commonly-used, say use feature ‘formats’” in one version of Perl, and emit warnings if people don’t explicitly use the feature. Sam -- Website: http://www.illuminated.co.uk/
Subject: Re: [perl #132013] 'no formats'
From: Sawyer X <xsawyerx [...] gmail.com>
To: Zefram <zefram [...] fysh.org>, perl5-porters [...] perl.org
Date: Mon, 4 Sep 2017 11:18:41 +0300

On 09/01/2017 09:07 PM, Zefram wrote:
Show quoted text
Ed Avis wrote:
This is useful because of the fair number of format-only special
variables such as $- and $=, whose existence tends to make it harder
to detect typos in code.
I don't think this justifies a core feature, at least not yet.
It would be possible for a CPAN module to disable the use of those magic
variables, so that would seem to satisfy your use case.  (In fact my
module IO::ExplicitHandle does disable a bunch of them, along with the
implicit-handle form of some ops.)  If such a stricture module becomes
very popular then we might consider implementing it in the core in
some form.

Thinking in terms of a stricture that disables magic variables,
taking out only the format-related ones doesn't seem the most useful
approach.  Nor does it seem useful to disable other aspects of formats.
It would probably be better for a stricture to disable *all* of the
punctuation-named variables, with the exception of ones listed in the
"use" invocation.  Effectively requiring declaration of each magic
variable before use.  So you'd say something like

	use strict::punctuation qw(except $_ $@);

I actually like this idea.

Show quoted text
use punctuation qw( $_ @_ $@ $! );
no punctuation qw( $- );

RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 3.3k
Thanks to everyone who has replied. First to say something about formats. I haven't used them, and in my personal and subjective experience, they seem like a relic from another age; one of fixed-width terminal output and monospaced hard copy. If I wanted something fancier than plain text output with the occasional tab, I would generate HTML; for printed documentation I'd use a toolchain that makes PDFs. And what I said here was equally true twenty years ago. However, that is not by any means a reason to remove formats or even to provide a way to disable them. As Abigail notes, it doesn't improve maintainability of the core because now you have two modes to support, with and without formats. And who knows, there may be programmers who make regular use of them. So this bug is not intended as "I do not like formats; please get rid of them". The particular issue is the punctuation variables associated with formats. There are six and some of these two-character sequences can often appear as typos. The common typing mistakes vary by programmer; I often type $->[0] instead of $_->[0] but I can imagine others making mistakes with $% when first learning about how to use hash references. So it's not really the same as threads or dbmopen(), or even dump(), which may not be much used, but don't affect the language syntax. Perlcritic is a great tool and I use it regularly, but it isn't a replacement for error and warning checking in the language itself. For me at least, it's something to look at as a regular report but not every single time you edit and run the program. If the normal edit-test cycle is to be replaced by edit-perlcritic-test, development becomes a lot slower. As others have noted, perlcritic tends to need a lot of customization and adaptation. It's certainly worth it in the long term, but the more guru-ish issues raised by perlcritic are in a different class from a mistyped variable name. I see it as analogous to "use strict". Why should perl check for mistyped variable names when it's perfectly legal to have both $transformed and $tansformed in your code, and perfectly legal to call &{"hello"}()? You can always have a perlcritic policy for that. And it means that the perl core now has to support running both with 'strict' and without. Yet checking for these typos saves so much development time, and doing it in the core is much faster than as an external linter, that it's worth having (and in my opinion, is one of the big plus points for Perl compared with other scripting languages). Zefram's idea of disabling particular punctuation variables may be the way to go. As noted, the bug is not really about formats but just about $-, $% and so on, which are never used in most programs but have the effect of hiding typos and language misunderstandings. A pragma "no format_vars" would turn these off at compile time (and, perhaps, the longer named but still odd variables like $ACCUMULATOR). You could still use formats with the IO::Handle named methods, or just "use format_vars" for a particular section of code. Or if you forget the emphasis on formats and just cover magic variables in general, it could be used to address what I feel is another of the "paper cuts" in the language, the special behaviour of $a and $b. The crystal chamber could be used to change these to ordinary variable names. -- Ed Avis <eda@waniasset.com>
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 440b
On Mon, 04 Sep 2017 02:01:24 -0700, ed wrote: Show quoted text
> The particular issue is the punctuation variables associated with > formats. There are six and some of these two-character sequences can > often appear as typos. The common typing mistakes vary by programmer; > I often type $->[0] instead of $_->[0] but I can imagine others making > mistakes with $% when first learning about how to use hash references.
Something like the attached? Tony
Subject: 0001-perl-132013-implement-strict-punctuation.patch
From cc93575397fe3016d970743ca9727aa19a83bb49 Mon Sep 17 00:00:00 2001 From: Tony Cook <tony@develop-help.com> Date: Thu, 19 Oct 2017 16:43:51 +1100 Subject: (perl #132013) implement strict::punctuation --- MANIFEST | 2 + Porting/Maintainers.pl | 1 + gv.c | 52 +++++++++++ lib/strict/punctuation.pm | 214 ++++++++++++++++++++++++++++++++++++++++++++++ lib/strict/punctuation.t | 155 +++++++++++++++++++++++++++++++++ pod/perldiag.pod | 5 ++ 6 files changed, 429 insertions(+) create mode 100644 lib/strict/punctuation.pm create mode 100644 lib/strict/punctuation.t diff --git a/MANIFEST b/MANIFEST index 124812b..52413f1 100644 --- a/MANIFEST +++ b/MANIFEST @@ -4683,6 +4683,8 @@ lib/sort.pm For "use sort" lib/sort.t See if "use sort" works lib/strict.pm For "use strict" lib/strict.t See if strictures work +lib/strict/punctuation.pm Enable or disable punctuation variables +lib/strict/punctuation.t See if strict::punctuation works lib/subs.pm Declare overriding subs lib/subs.t See if subroutine pseudo-importation works lib/Symbol.pm Symbol table manipulation routines diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl index 9c8c128..68e95b4 100755 --- a/Porting/Maintainers.pl +++ b/Porting/Maintainers.pl @@ -1437,6 +1437,7 @@ use File::Glob qw(:case); lib/sigtrap.{pm,t} lib/sort.{pm,t} lib/strict.{pm,t} + lib/strict/punctuation.{pm,t} lib/subs.{pm,t} lib/unicore/ lib/utf8.{pm,t} diff --git a/gv.c b/gv.c index fed5b7c..9d2b0b8 100644 --- a/gv.c +++ b/gv.c @@ -1766,6 +1766,36 @@ S_gv_is_in_main(pTHX_ const char *name, STRLEN len, const U32 is_utf8) return FALSE; } +static int +punct_bit_number(svtype sv_type, U8 ch) { + /* This needs to match _punct_bit() in strict::punctation */ + int base = sv_type == SVt_PV ? 0 : + sv_type == SVt_PVAV ? 1 : + sv_type == SVt_PVHV ? 2 : -1; + ch = NATIVE_TO_LATIN1(ch); + + assert(sv_type == SVt_PV || sv_type == SVt_PVAV || sv_type == SVt_PVHV); + if (ch == 95) { /* _ */ + return base; + } + else if (ch >= 33 && ch < 48) { /* ! .. / */ + return base + 3 * (ch - 32); + } + else if (ch >= 58 && ch < 65) { /* : .. @ */ + return base + 3 * (ch - 42); + } + else if (ch >= 91 && ch < 97) { /* [ .. ^ */ + /* yes, this leaves an unused bit for _ */ + return base + 3 * (ch - 68); + } + else if (ch == 126) { /* ~ */ + return base + 3 * (ch - 97); + } + else { + return -1; + } +} + /* This function is called if parse_gv_stash_name() failed to * find a stash, or if GV_NOTQUAL or an empty name was passed @@ -1784,7 +1814,29 @@ S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len, /* No stash in name, so see how we can default */ if ( gv_is_in_main(name, len, is_utf8) ) { + int bit; + SV *punct_bits; + *stash = PL_defstash; + if (IN_PERL_COMPILETIME && add && + (PL_hints & HINT_LOCALIZE_HH) != 0 && + (sv_type == SVt_PV || sv_type == SVt_PVAV || sv_type == SVt_PVHV) && + len == 1 && + (bit = punct_bit_number(sv_type, (U8)*name)) != -1 && + (punct_bits = cop_hints_fetch_pvs(PL_curcop, "strict::punctuation", 0)) != &PL_sv_placeholder + ) { + STRLEN len; + U8 *bits = (U8*)SvPV(punct_bits, len); + if (Off((unsigned)bit) >= len || !IsSet(bits, (unsigned)bit)) { + qerror(Perl_mess(aTHX_ + "Punctuation variable '%s%s' disabled by strict::punctuation", + (sv_type == SVt_PV ? "$" + : sv_type == SVt_PVAV ? "@" + : sv_type == SVt_PVHV ? "%" + : ""), name)); + } + } + } else { if (IN_PERL_COMPILETIME) { diff --git a/lib/strict/punctuation.pm b/lib/strict/punctuation.pm new file mode 100644 index 0000000..170b8c9 --- /dev/null +++ b/lib/strict/punctuation.pm @@ -0,0 +1,214 @@ +package strict::punctuation; +use strict; +use warnings; +use v5.26.0; + +our $VERSION = '1.000'; + +our @CARP_NOT = __PACKAGE__; + +sub _croak { + require Carp; + goto &Carp::croak; +} + +sub _punct_bit { + # we want ASCII-ish numbering here + my $o = ord(utf8::native_to_unicode(substr($_[0], 1))); + my $sigil = substr($_[0], 0, 1); + my $base = + $sigil eq '$' ? 0 : + $sigil eq '@' ? 1 : + $sigil eq '%' ? 2 : + return; + if ($o == 95) { # _ + return $base; + } + elsif ($o >= 33 && $o < 48) { + return $base + 3 * ($o - 32); + } + elsif ($o >= 58 && $o < 65) { + return $base + 3 * ($o - 42); + } + elsif ($o >= 91 && $o < 97) { + # yes, this leaves an unused bit for _ + return $base + 3 * ($o - 68); + } + elsif ($o == 126) { + return $base + 3 * ($o - 97); + } + else { + return; + } +} + +my $def_bits; +my $all_bits; +my $key = "strict::punctuation"; +{ + vec($def_bits, _punct_bit('$_'), 1) = 1; + vec($def_bits, _punct_bit('@_'), 1) = 1; + $all_bits = "\xFF" x ((_punct_bit('%~') + 7) / 8); +} + +my %groups = + ( + regex => [ qw($& $` $' $+ @+ %+ @- %-) ], + formats => [ qw($% $: $= $^ $~) ], + users => [ qw($< $>) ], + groups => [ qw[$( $)] ], + files => [ qw($. $/ $\ $|), '$,' ], + errors => [ qw($! $@ $? %!) ], + ); + +sub _do_bits { + my $value = shift; + + my $bits = $^H{$key} || $def_bits; + if (@_) { + if ($_[0] eq ':none') { + shift; + $bits = $value ? '' : $all_bits; + } + elsif ($_[0] eq ':all') { + shift; + $bits = $value ? $all_bits : ''; + } + } + while (defined(my $var = shift)) { + if ($var =~ s/^://) { + $groups{$var} + or _croak("Unknown punctuation variable group :$var"); + unshift @_, @{$groups{$var}}; + } + elsif ($var =~ s/^-://) { + $groups{$var} + or _croak("Unknown punctuation variable group :$var"); + unshift @_, map "-$_", @{$groups{$var}}; + } + else { + my $set = $value; + $set = !$set if $var =~ s/^-//; + my $bit = _punct_bit($var); + defined $bit + or _croak("Unknown punctuation variable $var"); + vec($bits, $bit, 1) = $set; + } + } + $bits =~ s/\0+\z//g; + if ($bits eq $all_bits) { + delete $^H{$key}; + } + else { + $^H{$key} = $bits; + } +} + +sub import { + shift; + _do_bits(1, @_); +} + +sub unimport { + shift; + _do_bits(0, @_); +} + +1; + +=head1 NAME + +strict::punctuation - disable/enable punctuation variables lexically + +=head1 SYNOPSIS + + use strict::punctuation; + # only $_ and @_ enabled + use strict::punctuation '$!'; + # can now use $! + use strict::punctuation ':errors'; + # can now use $!, $@, $? and %! + no strict::punctuation ':errors'; + # can't use $! etc + +=head1 DESCRIPTION + +The C<strict::punctuation> pragma disables most punctuation variables +to prevent accidental use of the wrong variables. + +By default the C<$_> and C<@_> variables remain enabled, but they can +also be disabled by explicitly disabling them, or with the C<:none> +group: + + use strict::punctuation qw(-$_ -@_); + no strict::punctuation qw($_ @_); + use strict::punctuation ':none'; + +You can enable or disable punctuation variables either individually or +in groups: + + use strict::punctuation qw($! $@ $? %!); + use strict::punctuation ':errors'; + +You can prefix a variable name or most groups to reverse the +operation: + + use strict::punctuation '-$!'; # disable $! + no strict::punctuation '-$!'; # enable $! + +This is most useful when combining elements: + + # enable all error variables except for $? + use strict::punctuation ':errors', '-$?'; + +=head2 Variable Groups + +=over + +=item * + +C<:all> - all punctuation variables. This can only be at the +beginning of the import list and cannot be negated. + + # enable all but $! + use strict::punctuation ':all', '-$!'; + +=item * + +C<:none> - no variables. This can only be at the beginning of the +import list and cannot be negated. + + # only $! is enabled + use strict::punctuation ':none', '$!'; + +=item * + +C<:regex> - enable regular expression punctuation variables. C<$&>, +C<$`>, C<$'>, C<$+>, C<@+>, C<%+>, C<@-> and C<%->. + +=item * + +C<:formats:> - enable punctuation variables associated with formats. +C<$%>, C<$:>, C<$=>, C<$^> and C<$~>. + +=item * + +C<:users> - the C<< $< >> and C<< $> >> variables. + +=item * + +C<:groups> - the C<$(> and C<$)> variables. + +=item * + +C<:files> - punctuation variables associated with file handling. +C<$.>, C<$/>, C<$\>, C<$|> and C<$,>. + +=item * + +C<:errors> - punctuation variables associated with errors. C<$!>, +C<$@>, C<$?> and C<%!>. + +=back + +=cut diff --git a/lib/strict/punctuation.t b/lib/strict/punctuation.t new file mode 100644 index 0000000..afe815c --- /dev/null +++ b/lib/strict/punctuation.t @@ -0,0 +1,155 @@ +#!perl + +BEGIN { + chdir 't' if -d 't'; + require "./test.pl"; + set_up_inc(".", "../lib"); +} + +run_multiple_progs('', \*DATA); + +done_testing(); + +__END__ +# NAME strict::punctuation defaults +use strict::punctuation; +my $x = $_; +my @x = @_; +my %x = %_; +$x = $!; +@x = @!; +%x = %!; +print "Fail\n"; +EXPECT +OPTIONS fatal +Punctuation variable '%_' disabled by strict::punctuation at - line 4. +Punctuation variable '$!' disabled by strict::punctuation at - line 5. +Punctuation variable '@!' disabled by strict::punctuation at - line 6. +Punctuation variable '%!' disabled by strict::punctuation at - line 7. +BEGIN not safe after errors--compilation aborted at - line 7. +######## +# NAME strict::punctuation disable $_ +no strict::punctuation '$_'; +my $x = $_; +use strict::punctuation '$_'; +my $y = $_; +EXPECT +OPTIONS fatal +Punctuation variable '$_' disabled by strict::punctuation at - line 2. +BEGIN not safe after errors--compilation aborted at - line 3. +######## +# NAME strict::punctuation disable $_ +my $z = $_; +no strict::punctuation '$_'; +my $x = $_; +use strict::punctuation '$_'; +my $y = $_; +EXPECT +OPTIONS fatal +Punctuation variable '$_' disabled by strict::punctuation at - line 3. +BEGIN not safe after errors--compilation aborted at - line 4. +######## +# NAME test - prefix +my $x = $_; +use strict::punctuation '-$_', '$!'; +die $!; +my $y = $_; +EXPECT +OPTIONS fatal +Punctuation variable '$_' disabled by strict::punctuation at - line 4. +Execution of - aborted due to compilation errors. +######## +# NAME strict::punctuation disable @_ +sub foo { + my @x = @_; + use strict::punctuation '@_'; + my @y = @_; + no strict::punctuation '@_'; + my @z = @_; +} +EXPECT +OPTIONS fatal +Punctuation variable '@_' disabled by strict::punctuation at - line 6. +Execution of - aborted due to compilation errors. +######## +# NAME regex group (and - on groups) +"a" =~ /(1)/; +my $x = $'; +my $y = $&; +my $z = $`; +my $w = $+; +my @x = @-; +my @y = @+; +my %x = %-; +my %y = %+; +use strict::punctuation ':regex'; +$x = $'; +$y = $&; +$z = $`; +$w = $+; +@x = @-; +@y = @+; +%x = %-; +%y = %+; +use strict::punctuation '-:regex'; +$x = $'; +$y = $&; +$z = $`; +$w = $+; +@x = @-; +@y = @+; +%x = %-; +%y = %+; +EXPECT +OPTIONS fatal +Punctuation variable '$'' disabled by strict::punctuation at - line 20. +Punctuation variable '$&' disabled by strict::punctuation at - line 21. +Punctuation variable '$`' disabled by strict::punctuation at - line 22. +Punctuation variable '$+' disabled by strict::punctuation at - line 23. +Punctuation variable '@-' disabled by strict::punctuation at - line 24. +Punctuation variable '@+' disabled by strict::punctuation at - line 25. +Punctuation variable '%-' disabled by strict::punctuation at - line 26. +Punctuation variable '%+' disabled by strict::punctuation at - line 27. +Execution of - aborted due to compilation errors. +######## +# NAME errors group +$! = 0; +$@ = ''; +$? = 0; +my @x = keys %!; +use strict::punctuation ':errors'; +$! = 0; +$@ = ''; +$? = 0; +@x = keys %!; +no strict::punctuation ':errors'; +$! = 0; +$@ = ''; +$? = 0; +my @x = keys %!; +EXPECT +OPTIONS fatal +Punctuation variable '$!' disabled by strict::punctuation at - line 11. +Punctuation variable '$@' disabled by strict::punctuation at - line 12. +Punctuation variable '$?' disabled by strict::punctuation at - line 13. +Punctuation variable '%!' disabled by strict::punctuation at - line 14. +Execution of - aborted due to compilation errors. +######## +# NAME all group +use strict::punctuation ':all'; +my $x = $_; +no strict::punctuation ':all'; +my $x = $_; +EXPECT +OPTIONS fatal +Punctuation variable '$_' disabled by strict::punctuation at - line 4. +Execution of - aborted due to compilation errors. +######## +# NAME none group +use strict::punctuation ':none', '$!'; +my $x = $_; +$! = 0; +EXPECT +OPTIONS fatal +Punctuation variable '$_' disabled by strict::punctuation at - line 2. +Execution of - aborted due to compilation errors. diff --git a/pod/perldiag.pod b/pod/perldiag.pod index d417fb2..43c3cde 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -5079,6 +5079,11 @@ the sub name and via the prototype attribute. The prototype in parentheses is useless, since it will be replaced by the prototype from the attribute before it's ever used. +=item Punctuation variable '%s' disabled by strict::punctuation + +(F) You've attemptted to use a punctuation variable that you've +disabled with the L<strict::punctuation> pragma. + =item Quantifier follows nothing in regex; marked by S<<-- HERE> in m/%s/ (F) You started a regular expression with a quantifier. Backslash it if -- 2.1.4
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 723b
On Mon, 23 Oct 2017 22:10:46 -0700, tonyc wrote: Show quoted text
>Something like the attached?
Yes, that looks great (based on reading the documentation). Although you have provided a few canned presets, I envisage that the exact selection would often be done in a 'style' module like Modern::Perl. Personally, I would set it to a small change at first, only disabling those punctuation variables which are truly obscure and obsolete, like $[. (I do still like the idea of 'no formats', with 'use formats' enabling both the format keywords and the associated punctuation variables, but I understand that it's kind of unrelated to the key issue in this bug, which is to get more useful diagnostics out of the parser for typing errors.)
RT-Send-CC: perl5-porters [...] perl.org
And thank you!


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org