Skip to content

Commit ec5fbb0

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 5332f20 commit ec5fbb0

File tree

7 files changed

+171
-0
lines changed

7 files changed

+171
-0
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
@@ -169,7 +169,10 @@
169169
# define ck_warner_d(a,...) Perl_ck_warner_d(aTHX_ a,__VA_ARGS__)
170170
# define clear_defarray(a,b) Perl_clear_defarray(aTHX_ a,b)
171171
# define clear_defarray_simple(a) Perl_clear_defarray_simple(aTHX_ a)
172+
# define cop_disable_warning(a,b) Perl_cop_disable_warning(aTHX_ a,b)
173+
# define cop_enable_warning(a,b) Perl_cop_enable_warning(aTHX_ a,b)
172174
# define cop_fetch_label(a,b,c) Perl_cop_fetch_label(aTHX_ a,b,c)
175+
# define cop_has_warning(a,b) Perl_cop_has_warning(aTHX_ a,b)
173176
# define cop_store_label(a,b,c,d) Perl_cop_store_label(aTHX_ a,b,c,d)
174177
# define croak_memory_wrap Perl_croak_memory_wrap
175178
# define croak_no_modify Perl_croak_no_modify

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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use warnings;
2+
use strict;
3+
use Test::More tests => 4;
4+
5+
use XS::APItest;
6+
7+
{
8+
use warnings;
9+
XS::APItest::test_cop_warnings(1);
10+
ok 1;
11+
}
12+
13+
{
14+
no warnings;
15+
XS::APItest::test_cop_warnings(0);
16+
ok 2;
17+
}
18+
{
19+
no warnings;
20+
use warnings qw( once );
21+
XS::APItest::test_cop_warnings(0);
22+
ok 3;
23+
}
24+
25+
{
26+
no warnings;
27+
use warnings qw( uninitialized );
28+
XS::APItest::test_cop_warnings(1);
29+
ok 4;
30+
}
31+
32+
1;

op.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9069,6 +9069,99 @@ 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+
char *warning_bits = cop->cop_warnings;
9088+
if(warning_bits == pWARN_ALL)
9089+
return true;
9090+
else if(warning_bits == pWARN_NONE)
9091+
return false;
9092+
else
9093+
return isWARN_on(cop->cop_warnings, warn_bit);
9094+
}
9095+
9096+
#define cop_inplace_expand_warning_bitmask(cop) S_cop_inplace_expand_warning_bitmask(aTHX_ cop)
9097+
STATIC void
9098+
S_cop_inplace_expand_warning_bitmask(pTHX_ COP *cop)
9099+
{
9100+
char *warning_bits = cop->cop_warnings;
9101+
9102+
if(warning_bits == pWARN_STD || warning_bits == pWARN_ALL)
9103+
warning_bits = WARN_ALLstring;
9104+
else if(warning_bits == pWARN_NONE)
9105+
warning_bits = WARN_NONEstring;
9106+
9107+
/* Must allocate the new one before we throw the old buffer away */
9108+
char *new_warnings = Perl_new_warnings_bitfield(aTHX_ NULL, warning_bits, WARNsize);
9109+
free_and_set_cop_warnings(cop, new_warnings);
9110+
}
9111+
9112+
/*
9113+
=for apidoc cop_enable_warning
9114+
9115+
Ensures that the set of warning bits contained by the COP includes the given
9116+
warning, as specified by one of the C<WARN_...> constants from F<warnings.h>.
9117+
9118+
If the COP already includes the warning, no modification is made. Otherwise,
9119+
the stored warning bitmask is cloned, and the given warning bit is enabled
9120+
within it.
9121+
9122+
=cut
9123+
*/
9124+
9125+
void
9126+
Perl_cop_enable_warning(pTHX_ COP *cop, int warn_bit)
9127+
{
9128+
PERL_ARGS_ASSERT_COP_ENABLE_WARNING;
9129+
9130+
if(cop_has_warning(cop, warn_bit))
9131+
return;
9132+
9133+
cop_inplace_expand_warning_bitmask(cop);
9134+
9135+
cop->cop_warnings[Perl_Warn_Off_(2 * warn_bit)] |= Perl_Warn_Bit_(2 * warn_bit);
9136+
}
9137+
9138+
/*
9139+
=for apidoc cop_disable_warning
9140+
9141+
Ensures that the set of warning bits contained by the COP does not include the
9142+
given warning, as specified by one of the C<WARN_...> constants from
9143+
F<warnings.h>.
9144+
9145+
If the COP does not include the warning, no modification is made. Otherwise,
9146+
the stored warning bitmask is cloned, and the given warning bit is disabled
9147+
within it.
9148+
9149+
=cut
9150+
*/
9151+
9152+
void
9153+
Perl_cop_disable_warning(pTHX_ COP *cop, int warn_bit)
9154+
{
9155+
PERL_ARGS_ASSERT_COP_DISABLE_WARNING;
9156+
9157+
if(!cop_has_warning(cop, warn_bit))
9158+
return;
9159+
9160+
cop_inplace_expand_warning_bitmask(cop);
9161+
9162+
cop->cop_warnings[Perl_Warn_Off_(2 * warn_bit)] &= ~Perl_Warn_Bit_(2 * warn_bit);
9163+
}
9164+
90729165
/*
90739166
=for apidoc newLOGOP
90749167

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)