summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Crane <arc@cpan.org>2015-06-29 16:35:11 +0100
committerAaron Crane <arc@cpan.org>2015-07-15 14:25:05 +0100
commit082ce9c667e6d73783164fa1abab61806b678b4f (patch)
treeee60e924f608c41862fb838eec013112895bd7c4
parent3e3bbb9b3cd1149bba698cb5d92fa3150db92d89 (diff)
downloadperl-082ce9c667e6d73783164fa1abab61806b678b4f.tar.gz
sv_vcatpvfn_flags(): make warnings more precise
- RT#125469 points out that no "redundant argument" warning should be emitted for code like C<< printf '<%*2$s>', "a", 6 >>; that's now fixed. - We no longer emit a "missing argument" warning for invalid format strings, so C<< printf '%4$K %d', 17 >> now emits one "invalid" warning, and no other warnings. (Perl 5.12 and subsequent versions have inappropriately emitted a "missing argument" warning in this case.) - We no longer treat the invalid format string in C<< printf '%1$$d', 17 >> as containing an explicit index, so (a) we emit an "invalid" warning for the double "$", and (b) we emit a "redundant argument" warning for the trailing argument. The "redundant argument" warning is new in this situation.
-rw-r--r--sv.c65
-rw-r--r--t/op/sprintf.t9
2 files changed, 46 insertions, 28 deletions
diff --git a/sv.c b/sv.c
index b4a36e51a0..d3debba72c 100644
--- a/sv.c
+++ b/sv.c
@@ -10594,16 +10594,16 @@ Perl_sv_vsetpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
/*
- * Warn of missing argument to sprintf, and then return a defined value
- * to avoid inappropriate "use of uninit" warnings [perl #71000].
+ * Warn of missing argument to sprintf. The value used in place of such
+ * arguments should be &PL_sv_no; an undefined value would yield
+ * inappropriate "use of uninit" warnings [perl #71000].
*/
-STATIC SV*
-S_vcatpvfn_missing_argument(pTHX) {
+STATIC void
+S_warn_vcatpvfn_missing_argument(pTHX) {
if (ckWARN(WARN_MISSING)) {
Perl_warner(aTHX_ packWARN(WARN_MISSING), "Missing argument in %s",
PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
}
- return &PL_sv_no;
}
@@ -11032,6 +11032,17 @@ S_hextract(pTHX_ const NV nv, int* exponent, U8* vhex, U8* vend)
return v;
}
+/* Helper for sv_vcatpvfn_flags(). */
+#define FETCH_VCATPVFN_ARGUMENT(var, in_range, expr) \
+ STMT_START { \
+ if (in_range) \
+ (var) = (expr); \
+ else { \
+ (var) = &PL_sv_no; /* [perl #71000] */ \
+ arg_missing = TRUE; \
+ } \
+ } STMT_END
+
void
Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
va_list *const args, SV **const svargs, const I32 svmax, bool *const maybe_tainted,
@@ -11087,7 +11098,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
sv_catsv_nomg(sv, *svargs);
}
else
- S_vcatpvfn_missing_argument(aTHX);
+ S_warn_vcatpvfn_missing_argument(aTHX);
return;
}
if (args && patlen == 3 && pat[0] == '%' &&
@@ -11161,6 +11172,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
STRLEN precis = 0;
const I32 osvix = svix;
bool is_utf8 = FALSE; /* is this item utf8? */
+ bool used_explicit_ix = FALSE;
+ bool arg_missing = FALSE;
#ifdef HAS_LDBL_SPRINTF_BUG
/* This is to try to fix a bug with irix/nonstop-ux/powerux and
with sfio - Allen <allens@cpan.org> */
@@ -11326,11 +11339,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
if (*q == '$') {
++q;
efix = width;
- if (!no_redundant_warning)
- /* I've forgotten if it's a better
- micro-optimization to always set this or to
- only set it if it's unset */
- no_redundant_warning = TRUE;
+ used_explicit_ix = TRUE;
} else {
goto gotwidth;
}
@@ -11371,9 +11380,12 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
tryasterisk:
if (*q == '*') {
q++;
- if ( (ewix = expect_number(&q)) )
- if (*q++ != '$')
+ if ( (ewix = expect_number(&q)) ) {
+ if (*q++ == '$')
+ used_explicit_ix = TRUE;
+ else
goto unknown;
+ }
asterisk = TRUE;
}
if (*q == 'v') {
@@ -11401,11 +11413,11 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
if (args)
vecsv = va_arg(*args, SV*);
else if (evix) {
- vecsv = (evix > 0 && evix <= svmax)
- ? svargs[evix-1] : S_vcatpvfn_missing_argument(aTHX);
+ FETCH_VCATPVFN_ARGUMENT(
+ vecsv, evix > 0 && evix <= svmax, svargs[evix-1]);
} else {
- vecsv = svix < svmax
- ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX);
+ FETCH_VCATPVFN_ARGUMENT(
+ vecsv, svix < svmax, svargs[svix++]);
}
dotstr = SvPV_const(vecsv, dotstrlen);
/* Keep the DO_UTF8 test *after* the SvPV call, else things go
@@ -11573,11 +11585,10 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
if (!vectorize && !args) {
if (efix) {
const I32 i = efix-1;
- argsv = (i >= 0 && i < svmax)
- ? svargs[i] : S_vcatpvfn_missing_argument(aTHX);
+ FETCH_VCATPVFN_ARGUMENT(argsv, i >= 0 && i < svmax, svargs[i]);
} else {
- argsv = (svix >= 0 && svix < svmax)
- ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX);
+ FETCH_VCATPVFN_ARGUMENT(argsv, svix >= 0 && svix < svmax,
+ svargs[svix++]);
}
}
@@ -11680,7 +11691,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
if (vectorize) {
STRLEN ulen;
if (!veclen)
- continue;
+ goto donevalidconversion;
if (vec_utf8)
uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
UTF8_ALLOW_ANYUV);
@@ -11785,7 +11796,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
STRLEN ulen;
vector:
if (!veclen)
- continue;
+ goto donevalidconversion;
if (vec_utf8)
uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
UTF8_ALLOW_ANYUV);
@@ -12447,7 +12458,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
}
else
sv_setuv_mg(argsv, has_utf8 ? (UV)sv_len_utf8(sv) : (UV)i);
- continue; /* not "break" */
+ goto donevalidconversion;
/* UNKNOWN */
@@ -12572,6 +12583,12 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
esignlen = 0;
goto vector;
}
+
+ donevalidconversion:
+ if (used_explicit_ix)
+ no_redundant_warning = TRUE;
+ if (arg_missing)
+ S_warn_vcatpvfn_missing_argument(aTHX);
}
/* Now that we've consumed all our printf format arguments (svix)
diff --git a/t/op/sprintf.t b/t/op/sprintf.t
index c927a94d67..e11287c6c4 100644
--- a/t/op/sprintf.t
+++ b/t/op/sprintf.t
@@ -647,7 +647,8 @@ __END__
>%y< >''< >%y INVALID REDUNDANT<
>%z< >''< >%z INVALID REDUNDANT<
>%2$d %1$d< >[12, 34]< >34 12<
->%*2$d< >[12, 3]< > 12 REDUNDANT<
+>%*2$d< >[12, 3]< > 12< >RT#125469<
+>%*3$d< >[12, 9, 3]< > 12< >related to RT#125469<
>%2$d %d< >[12, 34]< >34 12<
>%2$d %d %d< >[12, 34]< >34 12 34<
>%3$d %d %d< >[12, 34, 56]< >56 12 34<
@@ -655,8 +656,8 @@ __END__
>%*3$2$d %d< >[12, 34, 3]< >%*3$2$d 12 INVALID REDUNDANT<
>%2$d< >12< >0 MISSING<
>%0$d< >12< >%0$d INVALID REDUNDANT<
->%1$$d< >12< >%1$$d INVALID<
->%1$1$d< >12< >%1$1$d INVALID<
+>%1$$d< >12< >%1$$d INVALID REDUNDANT<
+>%1$1$d< >12< >%1$1$d INVALID REDUNDANT<
>%*2$*2$d< >[12, 3]< >%*2$*2$d INVALID REDUNDANT<
>%*2*2$d< >[12, 3]< >%*2*2$d INVALID REDUNDANT<
>%*2$1d< >[12, 3]< >%*2$1d INVALID REDUNDANT<
@@ -713,7 +714,7 @@ __END__
>%V-%s< >["Hello"]< >%V-Hello INVALID<
>%K %d %d< >[13, 29]< >%K 13 29 INVALID<
>%*.*K %d< >[13, 29, 76]< >%*.*K 13 INVALID REDUNDANT<
->%4$K %d< >[45, 67]< >%4$K 45 MISSING INVALID<
+>%4$K %d< >[45, 67]< >%4$K 45 INVALID REDUNDANT<
>%d %K %d< >[23, 45]< >23 %K 45 INVALID<
>%*v*999\$d %d %d< >[11, 22, 33]< >%*v*999\$d 11 22 INVALID REDUNDANT<
>%#b< >0< >0<