Skip to content

Commit 215e36f

Browse files
committed
Add cop_*_warning() API
This adds three new API functions: a pair to modify a COP by enabling or disabling a single warning bit within it, and a query function to ask if a given warning is already enabled. This API is provided for CPAN modules to use to modify the set of warnings present in a COP during compile-time. Currently modules need to use the `new_warnings_bitfield()` function, which was recently hidden by 09a0707. That change broke the `Syntax::Keyword::Try` module, as reported in #23609.
1 parent 2f1473d commit 215e36f

File tree

8 files changed

+190
-1
lines changed

8 files changed

+190
-1
lines changed

MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5100,6 +5100,7 @@ ext/XS-APItest/t/callregexec.t XS::APItest: tests for CALLREGEXEC()
51005100
ext/XS-APItest/t/check_warnings.t test scope of "Too late for CHECK"
51015101
ext/XS-APItest/t/cleanup.t test stack behaviour on unwinding
51025102
ext/XS-APItest/t/clone-with-stack.t test clone with CLONEf_COPY_STACKS works
5103+
ext/XS-APItest/t/cop_warnings.t test cop_*_warning
51035104
ext/XS-APItest/t/cophh.t test COPHH API
51045105
ext/XS-APItest/t/coplabel.t test cop_*_label
51055106
ext/XS-APItest/t/copstash.t test alloccopstash

embed.fnc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,10 +898,18 @@ Rp |OP * |cmpchain_start |I32 type \
898898
|NULLOK OP *right
899899
ERTXp |const char *|cntrl_to_mnemonic \
900900
|const U8 c
901+
Adp |void |cop_disable_warning \
902+
|NN COP *cop \
903+
|int warn_bit
904+
Adp |void |cop_enable_warning \
905+
|NN COP *cop \
906+
|int warn_bit
901907
Adpx |const char *|cop_fetch_label \
902908
|NN COP * const cop \
903909
|NULLOK STRLEN *len \
904910
|NULLOK U32 *flags
911+
Adp |bool |cop_has_warning|NN const COP *cop \
912+
|int warn_bit
905913
: Only used in op.c and the perl compiler
906914
Adpx |void |cop_store_label|NN COP * const cop \
907915
|NN const char *label \

embed.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,10 @@
167167
# define ck_warner_d(a,...) Perl_ck_warner_d(aTHX_ a,__VA_ARGS__)
168168
# define clear_defarray(a,b) Perl_clear_defarray(aTHX_ a,b)
169169
# define clear_defarray_simple(a) Perl_clear_defarray_simple(aTHX_ a)
170+
# define cop_disable_warning(a,b) Perl_cop_disable_warning(aTHX_ a,b)
171+
# define cop_enable_warning(a,b) Perl_cop_enable_warning(aTHX_ a,b)
170172
# define cop_fetch_label(a,b,c) Perl_cop_fetch_label(aTHX_ a,b,c)
173+
# define cop_has_warning(a,b) Perl_cop_has_warning(aTHX_ a,b)
171174
# define cop_store_label(a,b,c,d) Perl_cop_store_label(aTHX_ a,b,c,d)
172175
# define croak_memory_wrap Perl_croak_memory_wrap
173176
# define croak_no_modify Perl_croak_no_modify

ext/XS-APItest/APItest.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use strict;
44
use warnings;
55
use Carp;
66

7-
our $VERSION = '1.46';
7+
our $VERSION = '1.47';
88

99
require XSLoader;
1010

ext/XS-APItest/APItest.xs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,6 +3884,25 @@ test_coplabel()
38843884
if (len != 4) croak("fail # cop_fetch_label len");
38853885
if (!utf8) croak("fail # cop_fetch_label utf8");
38863886

3887+
void
3888+
test_cop_warnings(bool already_on)
3889+
PREINIT:
3890+
COP *cop = PL_curcop;
3891+
CODE:
3892+
if(cop_has_warning(cop, WARN_UNINITIALIZED) ^ already_on)
3893+
croak("fail # cop_has_warning initial state");
3894+
3895+
/* This code modfies PL_curcop which is normally quite rude, but we'll
3896+
* allow it during the test run.
3897+
*/
3898+
cop_enable_warning(cop, WARN_UNINITIALIZED);
3899+
if (!cop_has_warning(cop, WARN_UNINITIALIZED))
3900+
croak("fail # cop_enable_warning did not enable");
3901+
3902+
cop_disable_warning(cop, WARN_UNINITIALIZED);
3903+
if (cop_has_warning(cop, WARN_UNINITIALIZED))
3904+
croak("fail # cop_disable_warning did not disable");
3905+
38873906

38883907
HV *
38893908
example_cophh_2hv()

ext/XS-APItest/t/cop_warnings.t

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# no 'use warnings;' here so the first block sees defaults
2+
use strict;
3+
use Test::More tests => 6;
4+
5+
use XS::APItest;
6+
7+
{
8+
local $^W = 0;
9+
XS::APItest::test_cop_warnings(0);
10+
ok 1, "standard warnings with \$^W = 0";
11+
}
12+
13+
{
14+
local $^W = 1;
15+
XS::APItest::test_cop_warnings(1);
16+
ok 2, "standard warnings with \$^W = 1";
17+
}
18+
19+
{
20+
use warnings;
21+
XS::APItest::test_cop_warnings(1);
22+
ok 3, "'use warnings'";
23+
}
24+
25+
{
26+
no warnings;
27+
XS::APItest::test_cop_warnings(0);
28+
ok 4, "'no warnings'";
29+
}
30+
{
31+
no warnings;
32+
use warnings qw( once );
33+
XS::APItest::test_cop_warnings(0);
34+
ok 5, "'no warnings' + other";
35+
}
36+
37+
{
38+
no warnings;
39+
use warnings qw( uninitialized );
40+
XS::APItest::test_cop_warnings(1);
41+
ok 6, "'use warnings uninitialized'";
42+
}
43+
44+
1;

op.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9069,6 +9069,105 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
90699069
return op_prepend_elem(OP_LINESEQ, (OP*)cop, o);
90709070
}
90719071

9072+
/*
9073+
=for apidoc cop_has_warning
9074+
9075+
Returns true if the set of warnings bits contained by (or implied by) the
9076+
COP contains the given warning, as specified by one of the C<WARN_...>
9077+
constants from F<warnings.h>.
9078+
9079+
=cut
9080+
*/
9081+
9082+
bool
9083+
Perl_cop_has_warning(pTHX_ const COP *cop, int warn_bit)
9084+
{
9085+
PERL_ARGS_ASSERT_COP_HAS_WARNING;
9086+
9087+
const char *warning_bits = cop->cop_warnings;
9088+
if(warning_bits == pWARN_STD)
9089+
return (PL_dowarn & G_WARN_ON) ? true : PerlWarnIsSet_(WARN_DEFAULTstring, 2*warn_bit);
9090+
else if(warning_bits == pWARN_ALL)
9091+
return true;
9092+
else if(warning_bits == pWARN_NONE)
9093+
return false;
9094+
else
9095+
return isWARN_on(cop->cop_warnings, (STRLEN)warn_bit);
9096+
}
9097+
9098+
#define cop_inplace_expand_warning_bitmask(cop) S_cop_inplace_expand_warning_bitmask(aTHX_ cop)
9099+
STATIC void
9100+
S_cop_inplace_expand_warning_bitmask(pTHX_ COP *cop)
9101+
{
9102+
const char *warning_bits = cop->cop_warnings;
9103+
9104+
if(warning_bits == pWARN_STD)
9105+
warning_bits = (PL_dowarn & G_WARN_ON) ? WARN_ALLstring : WARN_DEFAULTstring;
9106+
else if(warning_bits == pWARN_ALL)
9107+
warning_bits = WARN_ALLstring;
9108+
else if(warning_bits == pWARN_NONE)
9109+
warning_bits = WARN_NONEstring;
9110+
9111+
/* Must allocate the new one before we throw the old buffer away */
9112+
char *new_warnings = Perl_new_warnings_bitfield(aTHX_ NULL, warning_bits, WARNsize);
9113+
free_and_set_cop_warnings(cop, new_warnings);
9114+
}
9115+
9116+
/*
9117+
=for apidoc cop_enable_warning
9118+
9119+
Ensures that the set of warning bits contained by the COP includes the given
9120+
warning, as specified by one of the C<WARN_...> constants from F<warnings.h>.
9121+
9122+
If the COP already includes the warning, no modification is made. Otherwise,
9123+
the stored warning bitmask is cloned, and the given warning bit is enabled
9124+
within it. The COP is modified in-place, and therefore this function is
9125+
intended only for use during compiletime when the optree is being constructed.
9126+
9127+
=cut
9128+
*/
9129+
9130+
void
9131+
Perl_cop_enable_warning(pTHX_ COP *cop, int warn_bit)
9132+
{
9133+
PERL_ARGS_ASSERT_COP_ENABLE_WARNING;
9134+
9135+
if(cop_has_warning(cop, warn_bit))
9136+
return;
9137+
9138+
cop_inplace_expand_warning_bitmask(cop);
9139+
9140+
cop->cop_warnings[Perl_Warn_Off_(2 * warn_bit)] |= Perl_Warn_Bit_(2 * warn_bit);
9141+
}
9142+
9143+
/*
9144+
=for apidoc cop_disable_warning
9145+
9146+
Ensures that the set of warning bits contained by the COP does not include the
9147+
given warning, as specified by one of the C<WARN_...> constants from
9148+
F<warnings.h>.
9149+
9150+
If the COP does not include the warning, no modification is made. Otherwise,
9151+
the stored warning bitmask is cloned, and the given warning bit is disabled
9152+
within it. The COP is modified in-place, and therefore this function is
9153+
intended only for use during compiletime when the optree is being constructed.
9154+
9155+
=cut
9156+
*/
9157+
9158+
void
9159+
Perl_cop_disable_warning(pTHX_ COP *cop, int warn_bit)
9160+
{
9161+
PERL_ARGS_ASSERT_COP_DISABLE_WARNING;
9162+
9163+
if(!cop_has_warning(cop, warn_bit))
9164+
return;
9165+
9166+
cop_inplace_expand_warning_bitmask(cop);
9167+
9168+
cop->cop_warnings[Perl_Warn_Off_(2 * warn_bit)] &= ~Perl_Warn_Bit_(2 * warn_bit);
9169+
}
9170+
90729171
/*
90739172
=for apidoc newLOGOP
90749173

proto.h

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)