Commit 631238ac by Martin Sebor Committed by Martin Sebor

PR translation/80280 - Missing closing quote (%>) c/semantics.c and c/c-typeck.c

gcc/c-family/ChangeLog:

	PR translation/80280
	* c-format.h (struct format_flag_spec): Add new member.
	(T89_T): New macro.
	* c-format.c (local_tree_type_node): New global.
	(printf_flag_specs, asm_fprintf_flag_spec): Initialize new data.
	(gcc_diag_flag_specs, scanf_flag_specs, strftime_flag_specs): Ditto.
	(strfmon_flag_specs): Likewise.
	(gcc_diag_char_table, gcc_cdiag_char_table): Split up specifiers
	with distinct quoting properties.
	(gcc_tdiag_char_table, gcc_cxxdiag_char_table): Same.
	(flag_chars_t::validate): Add argument and handle bad quoting.
	(check_format_info_main): Handle quoting problems.
	(init_dynamic_diag_info): Simplify.

gcc/testsuite/ChangeLog:

	PR translation/80280
	* gcc.dg/format/gcc_diag-10.c: New test.

From-SVN: r247778
parent 6ba86ba7
2017-05-08 Martin Sebor <msebor@redhat.com>
PR translation/80280
* c-format.h (struct format_flag_spec): Add new member.
(T89_T): New macro.
* c-format.c (local_tree_type_node): New global.
(printf_flag_specs, asm_fprintf_flag_spec): Initialize new data.
(gcc_diag_flag_specs, scanf_flag_specs, strftime_flag_specs): Ditto.
(strfmon_flag_specs): Likewise.
(gcc_diag_char_table, gcc_cdiag_char_table): Split up specifiers
with distinct quoting properties.
(gcc_tdiag_char_table, gcc_cxxdiag_char_table): Same.
(flag_chars_t::validate): Add argument and handle bad quoting.
(check_format_info_main): Handle quoting problems.
(init_dynamic_diag_info): Simplify.
2017-05-08 Jason Merrill <jason@redhat.com>
* c-opts.c (c_common_post_options): Update defaults for
......
......@@ -53,6 +53,9 @@ struct function_format_info
unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */
};
/* Initialized in init_dynamic_diag_info. */
static tree local_tree_type_node;
static bool decode_format_attr (tree, function_format_info *, int);
static int decode_format_type (const char *);
......@@ -492,17 +495,17 @@ static const format_length_info gcc_gfc_length_specs[] =
static const format_flag_spec printf_flag_specs[] =
{
{ ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
{ '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
{ '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
{ '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT },
{ 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
{ '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
{ '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
{ '\'', 0, 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT },
{ 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT },
{ 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
......@@ -516,15 +519,15 @@ static const format_flag_pair printf_flag_pairs[] =
static const format_flag_spec asm_fprintf_flag_specs[] =
{
{ ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
{ '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
{ '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
{ 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
{ '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
{ '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
{ 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
static const format_flag_pair asm_fprintf_flag_pairs[] =
......@@ -547,12 +550,12 @@ static const format_flag_pair gcc_diag_flag_pairs[] =
static const format_flag_spec gcc_diag_flag_specs[] =
{
{ '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 },
{ 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
{ '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
{ 'q', 0, 0, 1, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 },
{ 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
#define gcc_tdiag_flag_specs gcc_diag_flag_specs
......@@ -562,14 +565,14 @@ static const format_flag_spec gcc_diag_flag_specs[] =
static const format_flag_spec scanf_flag_specs[] =
{
{ '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
{ 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT },
{ 'm', 0, 0, N_("'m' flag"), N_("the 'm' scanf flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
{ '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT },
{ 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ '*', 0, 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
{ 'a', 0, 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT },
{ 'm', 0, 0, 0, N_("'m' flag"), N_("the 'm' scanf flag"), STD_EXT },
{ 'w', 0, 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
{ 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
{ '\'', 0, 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT },
{ 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
......@@ -583,16 +586,16 @@ static const format_flag_pair scanf_flag_pairs[] =
static const format_flag_spec strftime_flag_specs[] =
{
{ '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT },
{ '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT },
{ '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT },
{ '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT },
{ '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
{ 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 },
{ 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 },
{ 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ '_', 0, 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT },
{ '-', 0, 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT },
{ '0', 0, 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT },
{ '^', 0, 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT },
{ '#', 0, 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT },
{ 'w', 0, 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
{ 'E', 0, 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 },
{ 'O', 0, 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 },
{ 'O', 'o', 0, 0, NULL, N_("the 'O' modifier"), STD_EXT },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
......@@ -609,17 +612,17 @@ static const format_flag_pair strftime_flag_pairs[] =
static const format_flag_spec strfmon_flag_specs[] =
{
{ '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
{ '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 },
{ '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 },
{ '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 },
{ '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 },
{ '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 },
{ 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
{ '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
{ 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, STD_C89 }
{ '=', 0, 1, 0, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
{ '^', 0, 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 },
{ '+', 0, 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 },
{ '(', 0, 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 },
{ '!', 0, 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 },
{ '-', 0, 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 },
{ 'w', 0, 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
{ '#', 0, 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
{ 'p', 0, 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
{ 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
{ 0, 0, 0, 0, NULL, NULL, STD_C89 }
};
static const format_flag_pair strfmon_flag_pairs[] =
......@@ -685,10 +688,13 @@ static const format_char_info gcc_diag_char_table[] =
/* Custom conversion specifiers. */
/* These will require a "tree" at runtime. */
{ "K", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
{ "K", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "//cR", NULL },
{ "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL },
{ ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL },
{ "'" , 0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "R", 0, STD_C89, NOARGUMENTS, "", "\\", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
......@@ -706,12 +712,17 @@ static const format_char_info gcc_tdiag_char_table[] =
/* Custom conversion specifiers. */
/* These will require a "tree" at runtime. */
{ "DFKTEV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
{ "DFTV", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "'", NULL },
{ "E", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
{ "K", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
{ "v", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "/cR", NULL },
{ "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL },
{ ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL },
{ "'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "R", 0, STD_C89, NOARGUMENTS, "", "\\", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
{ "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
......@@ -730,12 +741,17 @@ static const format_char_info gcc_cdiag_char_table[] =
/* Custom conversion specifiers. */
/* These will require a "tree" at runtime. */
{ "DEFKTV", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
{ "DFTV", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "'", NULL },
{ "E", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
{ "K", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
{ "v", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "/cR", NULL },
{ "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL },
{ ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL },
{ "'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "R", 0, STD_C89, NOARGUMENTS, "", "\\", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
{ "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
......@@ -754,15 +770,19 @@ static const format_char_info gcc_cxxdiag_char_table[] =
/* Custom conversion specifiers. */
/* These will require a "tree" at runtime. */
{ "ADEFKSTVX",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL },
{ "ADFSTVX",1,STD_C89,{ T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "'", NULL },
{ "E", 1,STD_C89,{ T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL },
{ "K", 1, STD_C89,{ T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
{ "v", 0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL },
/* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */
{ "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "/cR", NULL },
{ "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL },
{ ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL },
{ "'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "R", 0, STD_C89, NOARGUMENTS, "", "\\", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
{ "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
......@@ -1689,7 +1709,8 @@ class flag_chars_t
tree format_string_cst,
location_t format_string_loc,
const char * const orig_format_chars,
char format_char);
char format_char,
bool quoted);
int get_alloc_flag (const format_kind_info *fki);
int assignment_suppression_p (const format_kind_info *fki);
......@@ -1849,10 +1870,13 @@ flag_chars_t::validate (const format_kind_info *fki,
tree format_string_cst,
location_t format_string_loc,
const char * const orig_format_chars,
char format_char)
char format_char,
bool quoted)
{
int i;
int d = 0;
bool quotflag = false;
for (i = 0; m_flag_chars[i] != 0; i++)
{
const format_flag_spec *s = get_flag_spec (flag_specs,
......@@ -1860,6 +1884,10 @@ flag_chars_t::validate (const format_kind_info *fki,
m_flag_chars[i - d] = m_flag_chars[i];
if (m_flag_chars[i] == fki->length_code_char)
continue;
/* Remember if a quoting flag is seen. */
quotflag |= s->quoting;
if (strchr (fci->flag_chars, m_flag_chars[i]) == 0)
{
format_warning_at_char (format_string_loc, format_string_cst,
......@@ -1891,8 +1919,30 @@ flag_chars_t::validate (const format_kind_info *fki,
format_char, fki->name);
}
}
/* Detect quoting directives used within a quoted sequence, such
as GCC's "%<...%qE". */
if (quoted && s->quoting)
{
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars - 1,
OPT_Wformat_,
"%s used within a quoted sequence",
_(s->name));
}
}
m_flag_chars[i - d] = 0;
if (!quoted
&& !quotflag
&& strchr (fci->flags2, '\''))
{
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"%qc conversion used unquoted",
format_char);
}
}
/* Determine if an assignment-allocation has been set, requiring
......@@ -2704,6 +2754,16 @@ check_format_info_main (format_check_results *res,
and it didn't use $; 1 if $ formats are in use. */
int has_operand_number = -1;
/* Vector of pointers to opening quoting directives (like GCC "%<"). */
auto_vec<const char*> quotdirs;
/* Pointers to the most recent color directives (like GCC's "%r or %R").
A starting color directive much be terminated before the end of
the format string. A terminating directive makes no sense without
a prior starting directive. */
const char *color_begin = NULL;
const char *color_end = NULL;
init_dollar_format_checking (info->first_arg_num, first_fillin_param);
while (*format_chars != 0)
......@@ -2785,11 +2845,72 @@ check_format_info_main (format_check_results *res,
flag_chars.validate (fki, fci, flag_specs, format_chars,
format_string_cst,
format_string_loc, orig_format_chars, format_char);
format_string_loc, orig_format_chars, format_char,
quotdirs.length () > 0);
const int alloc_flag = flag_chars.get_alloc_flag (fki);
const bool suppressed = flag_chars.assignment_suppression_p (fki);
/* Diagnose nested or unmatched quoting directives such as GCC's
"%<...%<" and "%>...%>". */
bool quot_begin_p = strchr (fci->flags2, '<');
bool quot_end_p = strchr (fci->flags2, '>');
if (quot_begin_p && !quot_end_p)
{
if (quotdirs.length ())
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"nested quoting directive");
quotdirs.safe_push (format_chars);
}
else if (!quot_begin_p && quot_end_p)
{
if (quotdirs.length ())
quotdirs.pop ();
else
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"unmatched quoting directive");
}
bool color_begin_p = strchr (fci->flags2, '/');
if (color_begin_p)
{
color_begin = format_chars;
color_end = NULL;
}
else if (strchr (fci->flags2, '\\'))
{
if (color_end)
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"%qc directive redundant after prior "
"occurence of the same", format_char);
else if (!color_begin)
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"unmatched color reset directive");
color_end = format_chars;
}
/* Diagnose directives that shouldn't appear in a quoted sequence.
(They are denoted by a double quote in FLAGS2.) */
if (quotdirs.length ())
{
if (strchr (fci->flags2, '"'))
format_warning_at_char (format_string_loc, format_string_cst,
format_chars - orig_format_chars,
OPT_Wformat_,
"%qc conversion used within a quoted "
"sequence",
format_char);
}
/* Validate the pairs of flags used. */
arg_parser.validate_flag_pairs (fci, format_char);
......@@ -2834,6 +2955,15 @@ check_format_info_main (format_check_results *res,
}
if (has_operand_number > 0)
finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
if (quotdirs.length ())
format_warning_at_char (format_string_loc, format_string_cst,
quotdirs.pop () - orig_format_chars,
OPT_Wformat_, "unterminated quoting directive");
if (color_begin && !color_end)
format_warning_at_char (format_string_loc, format_string_cst,
color_begin - orig_format_chars,
OPT_Wformat_, "unterminated color directive");
}
/* Check the argument types from a single format conversion (possibly
......@@ -3654,58 +3784,58 @@ init_dynamic_gfc_info (void)
static void
init_dynamic_diag_info (void)
{
static tree t, loc, hwi;
if (!loc || !t || !hwi)
/* For the GCC-diagnostics custom format specifiers to work, one
must have declared 'tree' and 'location_t' prior to using those
attributes. If we haven't seen these declarations then
the specifiers requiring these types shouldn't be used.
However we don't force a hard ICE because we may see only one
or the other type. */
if (tree loc = maybe_get_identifier ("location_t"))
{
static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci;
static format_length_info *diag_ls;
unsigned int i;
/* For the GCC-diagnostics custom format specifiers to work, one
must have declared 'tree' and/or 'location_t' prior to using
those attributes. If we haven't seen these declarations then
you shouldn't use the specifiers requiring these types.
However we don't force a hard ICE because we may see only one
or the other type. */
if ((loc = maybe_get_identifier ("location_t")))
{
loc = identifier_global_value (loc);
if (loc)
{
if (TREE_CODE (loc) != TYPE_DECL)
{
error ("%<location_t%> is not defined as a type");
loc = 0;
}
else
loc = TREE_TYPE (loc);
}
}
loc = identifier_global_value (loc);
if (loc && TREE_CODE (loc) != TYPE_DECL)
error ("%<location_t%> is not defined as a type");
}
/* Initialize the global tree node type local to this file. */
if (!local_tree_type_node
|| local_tree_type_node == void_type_node)
{
/* We need to grab the underlying 'union tree_node' so peek into
an extra type level. */
if ((t = maybe_get_identifier ("tree")))
if ((local_tree_type_node = maybe_get_identifier ("tree")))
{
t = identifier_global_value (t);
if (t)
local_tree_type_node = identifier_global_value (local_tree_type_node);
if (local_tree_type_node)
{
if (TREE_CODE (t) != TYPE_DECL)
if (TREE_CODE (local_tree_type_node) != TYPE_DECL)
{
error ("%<tree%> is not defined as a type");
t = 0;
local_tree_type_node = 0;
}
else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
else if (TREE_CODE (TREE_TYPE (local_tree_type_node))
!= POINTER_TYPE)
{
error ("%<tree%> is not defined as a pointer type");
t = 0;
local_tree_type_node = 0;
}
else
t = TREE_TYPE (TREE_TYPE (t));
local_tree_type_node =
TREE_TYPE (TREE_TYPE (local_tree_type_node));
}
}
else
local_tree_type_node = void_type_node;
}
/* Find the underlying type for HOST_WIDE_INT. For the %w
static tree hwi;
if (!hwi)
{
static format_length_info *diag_ls;
unsigned int i;
/* Find the underlying type for HOST_WIDE_INT. For the 'w'
length modifier to work, one must have issued: "typedef
HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
prior to using that modifier. */
......@@ -3757,75 +3887,17 @@ init_dynamic_diag_info (void)
else
gcc_unreachable ();
}
/* Handle the __gcc_diag__ format specifics. */
if (!diag_fci)
dynamic_format_types[gcc_diag_format_type].conversion_specs =
diag_fci = (format_char_info *)
xmemdup (gcc_diag_char_table,
sizeof (gcc_diag_char_table),
sizeof (gcc_diag_char_table));
if (t)
{
i = find_char_info_specifier_index (diag_fci, 'K');
diag_fci[i].types[0].type = &t;
diag_fci[i].pointer_count = 1;
}
/* Handle the __gcc_tdiag__ format specifics. */
if (!tdiag_fci)
dynamic_format_types[gcc_tdiag_format_type].conversion_specs =
tdiag_fci = (format_char_info *)
xmemdup (gcc_tdiag_char_table,
sizeof (gcc_tdiag_char_table),
sizeof (gcc_tdiag_char_table));
if (t)
{
/* All specifiers taking a tree share the same struct. */
i = find_char_info_specifier_index (tdiag_fci, 'D');
tdiag_fci[i].types[0].type = &t;
tdiag_fci[i].pointer_count = 1;
i = find_char_info_specifier_index (tdiag_fci, 'K');
tdiag_fci[i].types[0].type = &t;
tdiag_fci[i].pointer_count = 1;
}
/* Handle the __gcc_cdiag__ format specifics. */
if (!cdiag_fci)
dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
cdiag_fci = (format_char_info *)
xmemdup (gcc_cdiag_char_table,
sizeof (gcc_cdiag_char_table),
sizeof (gcc_cdiag_char_table));
if (t)
{
/* All specifiers taking a tree share the same struct. */
i = find_char_info_specifier_index (cdiag_fci, 'D');
cdiag_fci[i].types[0].type = &t;
cdiag_fci[i].pointer_count = 1;
i = find_char_info_specifier_index (cdiag_fci, 'K');
cdiag_fci[i].types[0].type = &t;
cdiag_fci[i].pointer_count = 1;
}
/* Handle the __gcc_cxxdiag__ format specifics. */
if (!cxxdiag_fci)
dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
cxxdiag_fci = (format_char_info *)
xmemdup (gcc_cxxdiag_char_table,
sizeof (gcc_cxxdiag_char_table),
sizeof (gcc_cxxdiag_char_table));
if (t)
{
/* All specifiers taking a tree share the same struct. */
i = find_char_info_specifier_index (cxxdiag_fci, 'D');
cxxdiag_fci[i].types[0].type = &t;
cxxdiag_fci[i].pointer_count = 1;
i = find_char_info_specifier_index (cxxdiag_fci, 'K');
cxxdiag_fci[i].types[0].type = &t;
cxxdiag_fci[i].pointer_count = 1;
}
}
/* It's safe to "re-initialize these to the same values. */
dynamic_format_types[gcc_diag_format_type].conversion_specs =
gcc_diag_char_table;
dynamic_format_types[gcc_tdiag_format_type].conversion_specs =
gcc_tdiag_char_table;
dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
gcc_cdiag_char_table;
dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
gcc_cxxdiag_char_table;
}
#ifdef TARGET_FORMAT_TYPES
......
......@@ -151,7 +151,16 @@ struct format_char_info
"W" if the argument is a pointer which is dereferenced and written into,
"R" if the argument is a pointer which is dereferenced and read from,
"i" for printf integer formats where the '0' flag is ignored with
precision, and "[" for the starting character of a scanf scanset. */
precision, and "[" for the starting character of a scanf scanset,
"<" if the specifier introduces a quoted sequence (such as "%<"),
">" if the specifier terminates a quoted sequence (such as "%>"),
"[" if the specifier introduces a color sequence (such as "%r"),
"]" if the specifier terminates a color sequence (such as "%R"),
"'" (single quote) if the specifier is expected to be quoted when
it appears outside a quoted sequence and unquoted otherwise (such
as the GCC internal printf format directive "%T"), and
"\"" (double quote) if the specifier is not expected to appear in
a quoted sequence (such as the GCC internal format directive "%K". */
const char *flags2;
/* If this format conversion character consumes more than one argument,
CHAIN points to information about the next argument. For later
......@@ -178,6 +187,8 @@ struct format_flag_spec
/* Nonzero if the next character after this flag in the format should
be skipped ('=' in strfmon), zero otherwise. */
int skip_next_char;
/* True if the flag introduces quoting (as in GCC's %qE). */
bool quoting;
/* The name to use for this flag in diagnostic messages. For example,
N_("'0' flag"), N_("field width"). */
const char *name;
......@@ -287,6 +298,7 @@ struct format_kind_info
#define T_UC &unsigned_char_type_node
#define T99_UC { STD_C99, NULL, T_UC }
#define T_V &void_type_node
#define T89_T { STD_C89, NULL, &local_tree_type_node }
#define T89_V { STD_C89, NULL, T_V }
#define T_W &wchar_type_node
#define T94_W { STD_C94, "wchar_t", T_W }
......
2017-05-08 Martin Sebor <msebor@redhat.com>
PR translation/80280
* gcc.dg/format/gcc_diag-10.c: New test.
2017-05-08 Kelvin Nilsen <kelvin@gcc.gnu.org>
PR target/80101
......
/* Test for GCC internal format directives.
{ dg-do compile }
{ dg-options "-std=gnu99 -Wformat" } */
/* Magic identifiers must be set before the attribute is used. */
typedef long long __gcc_host_wide_int__;
typedef struct location_s
{
const char *file;
int line;
} location_t;
union tree_node;
typedef union tree_node *tree;
#define FORMAT(kind) __attribute__ ((format (__gcc_## kind ##__, 1, 2)))
void diag (const char*, ...) FORMAT (diag);
void cdiag (const char*, ...) FORMAT (cdiag);
void tdiag (const char*, ...) FORMAT (tdiag);
void cxxdiag (const char*, ...) FORMAT (cxxdiag);
void test_diag (tree t)
{
diag ("%<"); /* { dg-warning "unterminated quoting directive" } */
diag ("%>"); /* { dg-warning "unmatched quoting directive " } */
diag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
diag ("%K", t);
diag ("%R"); /* { dg-warning "unmatched color reset directive" } */
diag ("%r", ""); /* { dg-warning "unterminated color directive" } */
diag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
diag ("%r%R", "");
diag ("%r%r%R", "", "");
diag ("%r%R%r%R", "", "");
diag ("%<%K%>", t); /* { dg-warning ".K. conversion used within a quoted sequence" } */
diag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
diag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
diag ("%<%r%R%>", "");
}
void test_cdiag (tree t)
{
cdiag ("%<"); /* { dg-warning "unterminated quoting directive" } */
cdiag ("%>"); /* { dg-warning "unmatched quoting directive " } */
cdiag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
cdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
cdiag ("%E", t);
cdiag ("%F", t); /* { dg-warning ".F. conversion used unquoted" } */
cdiag ("%K", t);
cdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
cdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
cdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
cdiag ("%r%R", "");
cdiag ("%r%r%R", "", "");
cdiag ("%r%R%r%R", "", "");
cdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
cdiag ("%V", t); /* { dg-warning ".V. conversion used unquoted" } */
cdiag ("%<%D%>", t);
cdiag ("%<%E%>", t);
cdiag ("%<%F%>", t);
cdiag ("%<%K%>", t); /* { dg-warning ".K. conversion used within a quoted sequence" } */
cdiag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
cdiag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
cdiag ("%<%r%R%>", "");
cdiag ("%<%T%>", t);
cdiag ("%<%V%>", t);
cdiag ("%<%qD%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
cdiag ("%<%qE%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
cdiag ("%<%qT%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
}
void test_tdiag (tree t)
{
tdiag ("%<"); /* { dg-warning "unterminated quoting directive" } */
tdiag ("%>"); /* { dg-warning "unmatched quoting directive " } */
tdiag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
tdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
tdiag ("%E", t);
tdiag ("%K", t);
tdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
tdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
tdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
tdiag ("%r%R", "");
tdiag ("%r%R", "");
tdiag ("%r%r%R", "", "");
tdiag ("%r%R%r%R", "", "");
tdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
tdiag ("%<%D%>", t);
tdiag ("%<%E%>", t);
tdiag ("%<%K%>", t); /* { dg-warning ".K. conversion used within a quoted sequence" } */
tdiag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
tdiag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
tdiag ("%<%r%R%>", "");
tdiag ("%<%T%>", t);
tdiag ("%<%qD%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
tdiag ("%<%qE%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
tdiag ("%<%qT%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
}
void test_cxxdiag (tree t)
{
cxxdiag ("%A", t); /* { dg-warning ".A. conversion used unquoted" } */
cxxdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
cxxdiag ("%E", t);
cxxdiag ("%F", t); /* { dg-warning ".F. conversion used unquoted" } */
cxxdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
cxxdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
cxxdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
cxxdiag ("%r%R", "");
cxxdiag ("%r%R", "");
cxxdiag ("%r%r%R", "", "");
cxxdiag ("%r%R%r%R", "", "");
cxxdiag ("%S", t); /* { dg-warning ".S. conversion used unquoted" } */
cxxdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
cxxdiag ("%V", t); /* { dg-warning ".V. conversion used unquoted" } */
cxxdiag ("%X", t); /* { dg-warning ".X. conversion used unquoted" } */
cxxdiag ("%<%A%>", t);
cxxdiag ("%<%D%>", t);
cxxdiag ("%<%E%>", t);
cxxdiag ("%<%F%>", t);
cxxdiag ("%<%R%>"); /* { dg-warning "unmatched color reset" } */
cxxdiag ("%<%r%R%>", "");
cxxdiag ("%<%S%>", t);
cxxdiag ("%<%T%>", t);
cxxdiag ("%<%V%>", t);
cxxdiag ("%<%X%>", t);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment