sub bits {
my $on = shift;
my $bits = 0;
+ my %seen; # Has flag already been seen?
ARG:
foreach my $idx (0..$#_){
my $s=$_[$idx];
&& $^H{reflags_charset} == $reflags{$_};
}
} elsif (exists $reflags{$_}) {
- $on
+ $seen{$_}++;
+ $on
? $reflags |= $reflags{$_}
: ($reflags &= ~$reflags{$_});
} else {
")");
}
}
+ if (exists $seen{'x'} && $seen{'x'} > 1
+ && (warnings::enabled("deprecated")
+ || warnings::enabled("regexp")))
+ {
+ my $message = "Having more than one /x regexp modifier is deprecated";
+ if (warnings::enabled("deprecated")) {
+ warnings::warn("deprecated", $message);
+ }
+ else {
+ warnings::warn("regexp", $message);
+ }
+ }
$bits;
}
use strict;
-use Test::More tests => 62;
+use Test::More tests => 63;
my @flags = qw( a d l u );
}
$w = "";
- eval "use re '/axaa'";
+ eval "use re '/amaa'";
like $w, qr/The "a" flag may only appear a maximum of twice/,
- "warning with eval \"use re \"/axaa\"";
+ "warning with eval \"use re \"/amaa\"";
+ $w = "";
+ eval "use re '/xamax'";
+ like $w, qr/Having more than one \/x regexp modifier is deprecated/,
+ "warning with eval \"use re \"/xamax\"";
}
=back
-[ List each other deprecation as a =head2 entry ]
+=head2 Use of multiple /x regexp modifiers
+
+It is now deprecated to say something like any of the following:
+
+ qr/foo/xx;
+ /(?xax:foo)/;
+ use re qw(/amxx);
+
+That is, now C<x> should only occur once in any string of contiguous
+regular expression pattern modifiers. We do not believe there are any
+occurrences of this in all of CPAN. This is in preparation for a future
+Perl release having C</xx> mean to allow white-space for readability in
+bracketed character classes (those enclosed in square brackets:
+C<[...]>).
=head1 Performance Enhancements
(F) The parser has given up trying to parse the program after 10 errors.
Further error messages would likely be uninformative.
+=item Having more than one /%c regexp modifier is deprecated
+
+(D deprecated, regexp) You used the indicated regular expression pattern
+modifier at least twice in a string of modifiers. It is deprecated to
+do this with this particular modifier, to allow future extensions to the
+Perl language.
+
=item Hexadecimal float: exponent overflow
(W overflow) The hexadecimal floating point has a larger exponent
regex_charset cs;
bool has_use_defaults = FALSE;
const char* const seqstart = RExC_parse - 1; /* Point to the '?' */
+ int x_mod_count = 0;
PERL_ARGS_ASSERT_PARSE_LPAREN_QUESTION_FLAGS;
switch (*RExC_parse) {
/* Code for the imsx flags */
- CASE_STD_PMMOD_FLAGS_PARSE_SET(flagsp);
+ CASE_STD_PMMOD_FLAGS_PARSE_SET(flagsp, x_mod_count);
case LOCALE_PAT_MOD:
if (has_charset_modifier) {
if (RExC_flags & RXf_PMf_FOLD) {
RExC_contains_i = 1;
}
+ if (PASS2) {
+ STD_PMMOD_FLAGS_PARSE_X_WARN(x_mod_count);
+ }
return;
/*NOTREACHED*/
default:
++RExC_parse;
}
+
+ if (PASS2) {
+ STD_PMMOD_FLAGS_PARSE_X_WARN(x_mod_count);
+ }
}
/*
#define RXf_PMf_STD_PMMOD (RXf_PMf_MULTILINE|RXf_PMf_SINGLELINE|RXf_PMf_FOLD|RXf_PMf_EXTENDED)
-#define CASE_STD_PMMOD_FLAGS_PARSE_SET(pmfl) \
- case IGNORE_PAT_MOD: *(pmfl) |= RXf_PMf_FOLD; break; \
- case MULTILINE_PAT_MOD: *(pmfl) |= RXf_PMf_MULTILINE; break; \
- case SINGLE_PAT_MOD: *(pmfl) |= RXf_PMf_SINGLELINE; break; \
- case XTENDED_PAT_MOD: *(pmfl) |= RXf_PMf_EXTENDED; break
+#define CASE_STD_PMMOD_FLAGS_PARSE_SET(pmfl, x_count) \
+ case IGNORE_PAT_MOD: *(pmfl) |= RXf_PMf_FOLD; break; \
+ case MULTILINE_PAT_MOD: *(pmfl) |= RXf_PMf_MULTILINE; break; \
+ case SINGLE_PAT_MOD: *(pmfl) |= RXf_PMf_SINGLELINE; break; \
+ case XTENDED_PAT_MOD: *(pmfl) |= RXf_PMf_EXTENDED; (x_count)++; break;
+
+#define STD_PMMOD_FLAGS_PARSE_X_WARN(x_count) \
+ if (UNLIKELY((x_count) > 1)) { \
+ Perl_ck_warner_d(aTHX_ packWARN2(WARN_DEPRECATED, WARN_REGEXP), \
+ "Having more than one /%c regexp modifier is deprecated", \
+ XTENDED_PAT_MOD); \
+ }
/* Note, includes charset ones, assumes 0 is the default for them */
#define STD_PMMOD_FLAGS_CLEAR(pmfl) \
'Unescaped left brace in regex is deprecated, passed through {#} m/\q{{#}/'
],
'/:{4,a}/' => 'Unescaped left brace in regex is deprecated, passed through {#} m/:{{#}4,a}/',
+ '/abc/xix' => 'Having more than one /x regexp modifier is deprecated',
+ '/(?xmsixp:abc)/' => 'Having more than one /x regexp modifier is deprecated',
+ '/(?xmsixp)abc/' => 'Having more than one /x regexp modifier is deprecated',
+ '/(?xxxx:abc)/' => 'Having more than one /x regexp modifier is deprecated',
);
while (my ($regex, $expect) = splice @death, 0, 2) {
}
static bool
-S_pmflag(pTHX_ const char* const valid_flags, U32 * pmfl, char** s, char* charset) {
+S_pmflag(pTHX_ const char* const valid_flags, U32 * pmfl, char** s, char* charset, unsigned int * x_mod_count) {
/* Adds, subtracts to/from 'pmfl' based on the next regex modifier flag
* found in the parse starting at 's', based on the subset that are valid
switch (c) {
- CASE_STD_PMMOD_FLAGS_PARSE_SET(pmfl);
+ CASE_STD_PMMOD_FLAGS_PARSE_SET(pmfl, *x_mod_count);
case GLOBAL_PAT_MOD: *pmfl |= PMf_GLOBAL; break;
case CONTINUE_PAT_MOD: *pmfl |= PMf_CONTINUE; break;
case ONCE_PAT_MOD: *pmfl |= PMf_KEEP; break;
const char * const valid_flags =
(const char *)((type == OP_QR) ? QR_PAT_MODS : M_PAT_MODS);
char charset = '\0'; /* character set modifier */
+ unsigned int x_mod_count = 0;
PERL_ARGS_ASSERT_SCAN_PAT;
pm->op_pmflags |= PMf_IS_QR;
}
- while (*s && S_pmflag(aTHX_ valid_flags, &(pm->op_pmflags), &s, &charset)) {};
+ while (*s && S_pmflag(aTHX_ valid_flags, &(pm->op_pmflags),
+ &s, &charset, &x_mod_count))
+ {};
/* issue a warning if /c is specified,but /g is not */
if ((pm->op_pmflags & PMf_CONTINUE) && !(pm->op_pmflags & PMf_GLOBAL))
{
"Use of /c modifier is meaningless without /g" );
}
+ STD_PMMOD_FLAGS_PARSE_X_WARN(x_mod_count);
+
PL_lex_op = (OP*)pm;
pl_yylval.ival = OP_MATCH;
return s;
line_t first_line;
I32 es = 0;
char charset = '\0'; /* character set modifier */
+ unsigned int x_mod_count = 0;
char *t;
PERL_ARGS_ASSERT_SCAN_SUBST;
s++;
es++;
}
- else if (! S_pmflag(aTHX_ S_PAT_MODS, &(pm->op_pmflags), &s, &charset))
+ else if (! S_pmflag(aTHX_ S_PAT_MODS, &(pm->op_pmflags),
+ &s, &charset, &x_mod_count))
{
break;
}
}
+ STD_PMMOD_FLAGS_PARSE_X_WARN(x_mod_count);
+
if ((pm->op_pmflags & PMf_CONTINUE)) {
Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless in s///" );
}