Skip to content

Commit

Permalink
Add support for new warning categories outside of "all"
Browse files Browse the repository at this point in the history
When someone suggests a new warning on p5p it always often up being
argued about on the basis that it'll break existing code, and that we
shouldn't add warnings for possibly legitimate code just because it's
unusual or odd.

As I pointed out in a discussion about RT #121025 (see [1]) we only keep
having this discussion because until now we've had no facility to add
new warnings outside of the default set that'll be retroactively enabled
for everything that does 'use warnings'. This patch introduces such a
facility.

As a proof of concept I'm adding a warning for something that was added
as a warning in the past, but pulled out because it was deemed too
controversial at the time: warning about the use of grep in void
context.

That warning was added back in v5.10.0-218-g74295f0 but quickly pulled
out in v5.10.0-230-gf5df478. See [2] for the discussion about it at the
time.

Now if you do:

    use warnings;
    grep /42/, (1,2);

You'll get no warnings as before, but if you do:

    use warnings qw(extra); # Or its sole subcategory: void_unusual
    grep /42/, (1,2);

You'll get a warning about "Unusual use of grep in void context". To
turn off this warning once you've turned it on it's *not* sufficient to
do:

    no warnings;

You need to do:

    no warnings qw(pedantic);

Or:

    no warnings qw(everything);

I'm willing to change that, but first we should ask ourselves whether
this should continue to remain a symmetric operation:

    {use,no} warnings ['all'];

There's more elaboration on how this works in the changes I'm making to
the perldelta and the warnings documentation. But briefly this should be
100% backwards compatible, but allow us to have our cake and eat it too
in the future by adding new warnings without imposing them on existing
code written against older perl versions (unless that code explicitly
requested to get new warnings as they upgrade perl).

The patch to the warnings.pm documentation lays out a backwards
compatibility policy for warnings, we promise that we'll continue the
status quo with the "all" category, but for other categories (including
future additions) we'll make such promises on a per-category basis.

TODO: I wanted to come up with some more general facility for being able
to add these new warnings without altering the behavior of the -w and -W
switches. I.e. now we'll emit this, as intended:

    $ ./perl -Ilib -w -e 'grep /42/, (1,2)'
    $ ./perl -Ilib -W -e 'grep /42/, (1,2)'
    $ ./perl -Ilib -e 'use warnings; grep /42/, (1,2)'
    $ ./perl -Ilib -e 'use warnings "extra"; grep /42/, (1,2)'
    Unusual use of grep in void context at -e line 1.

I.e. we don't want -w and -W to mean "use warnings 'everything'", it
should continue to mean "use warnings 'all'". But due to how they're
implemented I couldn't find an easy way to generalize this. Right now
I'm just hardcoding an exception to the new warning category I've added
outside "all" for these warnings.

That should be followed-up with a more general solution, but for now if
we only have a few of these catogeries we should be fine.

This patch incorporates work from Andreas Guðmundsson
<andreasg@nasarde.org> who picked up an earlier version of mine and
figured out the change being made to mg.c here. That change removes an
optimization in the ${^WARNING_BITS} magic which might make things a tad
slower.

1. https://rt.perl.org/Ticket/Display.html?id=121025#txn-1276663
2. http://www.nntp.perl.org/group/perl.perl5.porters/2007/12/msg131922.html
  • Loading branch information
Ævar Arnfjörð Bjarmason committed Dec 29, 2014
1 parent 0f83390 commit ea5519d
Show file tree
Hide file tree
Showing 13 changed files with 513 additions and 282 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -75,6 +75,7 @@ Ambrose Kofi Laing
Ammon Riley <ammon@rhythm.com>
Ananth Kesari <HYanantha@novell.com>
Anders Johnson <ajohnson@nvidia.com>
Andreas Guðmundsson <andreasg@nasarde.org>
Andreas Karrer <karrer@ife.ee.ethz.ch>
Andreas Klussmann <andreas@infosys.heitec.de>
Andreas König <a.koenig@mind.de>
Expand Down
12 changes: 6 additions & 6 deletions lib/B/Deparse.t
Expand Up @@ -1857,12 +1857,12 @@ my sub f {}
print f();
>>>>
use feature 'lexical_subs';
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005U\001"}
my sub f {
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005\001"}
}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005\001"}
print f();
####
# SKIP ?$] < 5.017004 && "lexical subs not implemented on this Perl version"
Expand All @@ -1873,13 +1873,13 @@ state sub f {}
print f();
>>>>
use feature 'lexical_subs';
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005U\001"}
CORE::state sub f {
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005\001"}
use feature 'state';
}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUU\005"}
BEGIN {${^WARNING_BITS} = "TUUUUUUUUUUUUTUT\005\001"}
use feature 'state';
print f();
####
Expand Down
400 changes: 245 additions & 155 deletions lib/warnings.pm

Large diffs are not rendered by default.

11 changes: 0 additions & 11 deletions mg.c
Expand Up @@ -2774,17 +2774,6 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
PerlMemShared_free(PL_compiling.cop_warnings);
PL_compiling.cop_warnings = pWARN_NONE;
}
/* Yuck. I can't see how to abstract this: */
else if (isWARN_on(
((STRLEN *)SvPV_nolen_const(sv)) - 1,
WARN_ALL)
&& !any_fatals)
{
if (!specialWARN(PL_compiling.cop_warnings))
PerlMemShared_free(PL_compiling.cop_warnings);
PL_compiling.cop_warnings = pWARN_ALL;
PL_dowarn |= G_WARN_ONCE ;
}
else {
STRLEN len;
const char *const p = SvPV_const(sv, len);
Expand Down
21 changes: 17 additions & 4 deletions op.c
Expand Up @@ -1765,6 +1765,7 @@ Perl_scalarvoid(pTHX_ OP *arg)
do {
SV *useless_sv = NULL;
const char* useless = NULL;
bool useless_is_grep = FALSE;

if (o->op_type == OP_NEXTSTATE
|| o->op_type == OP_DBSTATE
Expand Down Expand Up @@ -1884,9 +1885,15 @@ Perl_scalarvoid(pTHX_ OP *arg)
case OP_HELEM:
case OP_HSLICE:
if (!(o->op_private & (OPpLVAL_INTRO|OPpOUR_INTRO)))
/* Otherwise it's "Useless use of grep iterator" */
useless = OP_DESC(o);
break;
case OP_GREPWHILE:
if (!(o->op_private & (OPpLVAL_INTRO|OPpOUR_INTRO))) {
/* Otherwise it's "Useless use of grep iterator" */
useless = "grep";
useless_is_grep = TRUE;
}
break;

case OP_SPLIT:
kid = cLISTOPo->op_first;
Expand Down Expand Up @@ -2116,9 +2123,15 @@ Perl_scalarvoid(pTHX_ OP *arg)
SVfARG(sv_2mortal(useless_sv)));
}
else if (useless) {
Perl_ck_warner(aTHX_ packWARN(WARN_VOID),
"Useless use of %s in void context",
useless);
if (useless_is_grep) {
Perl_ck_warner(aTHX_ packWARN(WARN_VOID_UNUSUAL),
"Unusual use of %s in void context",
useless);
} else {
Perl_ck_warner(aTHX_ packWARN(WARN_VOID),
"Useless use of %s in void context",
useless);
}
}
} while ( (o = POP_DEFERRED_OP()) );

Expand Down
15 changes: 15 additions & 0 deletions pod/perldelta.pod
Expand Up @@ -27,6 +27,21 @@ here, but most should go in the L</Performance Enhancements> section.

[ List each enhancement as a =head2 entry ]

=head2 The warnings pragma now supports warnings outside of "all"

Ever since perl v5.6.0 we've had no way of adding new warnings without
retroactively adding them to all existing programs that used C<-w>,
C<-W> or C<use warnings>.

This caused us to not add new useful warnings out of fear that they
might unduly burden users who just wanted to upgrade perl and didn't
want to deal with a bunch of warnings from their existing code.

We now support a way to have our cake and eat it too, and can add new
warnings to the core going forward through other top-level warning
categories. See L<the warnings documentation|warnings/Top-level
warning categories & associated confusion> for details.

=head1 Security

XXX Any security-related notices go here. In particular, any security
Expand Down
11 changes: 11 additions & 0 deletions pod/perldiag.pod
Expand Up @@ -6473,6 +6473,17 @@ since they are often used in statements like
String constants that would normally evaluate to 0 or 1 are warned
about.

=item Unusual use of %s in void context

(W void_unusual) Similar to the "Useless use of %s in void context"
warning, but only turned on by the top-level "pedantic" warning
category, used for e.g. C<grep> in void context, which may indicate a
bug, but could also just be someone using C<grep> for its side-effects
as a loop.

Enabled as part of "extra" warnings, not in the "all" category. See
L<warnings> for details

=item Useless use of (?-p) in regex; marked by S<<-- HERE> in m/%s/

(W regexp) The C<p> modifier cannot be turned off once set. Trying to do
Expand Down
4 changes: 2 additions & 2 deletions pod/perlrun.pod
Expand Up @@ -925,13 +925,13 @@ of warnings; see L<warnings>.
=item B<-W>
X<-W>

Enables all warnings regardless of C<no warnings> or C<$^W>.
Enables "all" warnings regardless of C<no warnings> or C<$^W>.
See L<warnings>.

=item B<-X>
X<-X>

Disables all warnings regardless of C<use warnings> or C<$^W>.
Disables "all" warnings regardless of C<use warnings> or C<$^W>.
See L<warnings>.

=item B<-x>
Expand Down

0 comments on commit ea5519d

Please sign in to comment.