You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
-#include "toplev.h"
#include "c-common.h"
+#include "toplev.h"
#include "intl.h"
#include "diagnostic.h"
#include "langhooks.h"
format_type_error. Target-specific format types do not have
matching enum values. */
enum format_type { printf_format_type, asm_fprintf_format_type,
- gcc_diag_format_type, gcc_cdiag_format_type,
+ gcc_diag_format_type, gcc_tdiag_format_type,
+ gcc_cdiag_format_type,
gcc_cxxdiag_format_type,
scanf_format_type, strftime_format_type,
strfmon_format_type, format_type_error = -1};
if (info->format_type == format_type_error)
{
gcc_assert (!validated_p);
- warning (0, "%qE is an unrecognized format function type",
+ warning (OPT_Wformat, "%qE is an unrecognized format function type",
format_type_id);
return false;
}
};
/* The custom diagnostics all accept the same length specifiers. */
+#define gcc_tdiag_length_specs gcc_diag_length_specs
#define gcc_cdiag_length_specs gcc_diag_length_specs
#define gcc_cxxdiag_length_specs gcc_diag_length_specs
{ 0, 0, 0, 0 }
};
+#define gcc_tdiag_flag_pairs gcc_diag_flag_pairs
#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
static const format_flag_spec gcc_diag_flag_specs[] =
{
+ { '+', 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, 0 }
};
+#define gcc_tdiag_flag_specs gcc_diag_flag_specs
#define gcc_cdiag_flag_specs gcc_diag_flag_specs
static const format_flag_spec gcc_cxxdiag_flag_specs[] =
{ NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
};
+static const format_char_info gcc_tdiag_char_table[] =
+{
+ /* C89 conversion specifiers. */
+ { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+ { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+ { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+ { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+ { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL },
+ { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL },
+
+ /* Custom conversion specifiers. */
+
+ /* %H will require "location_t" at runtime. */
+ { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+
+ /* These will require a "tree" at runtime. */
+ { "DFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
+
+ { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
+ { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
static const format_char_info gcc_cdiag_char_table[] =
{
/* C89 conversion specifiers. */
{ "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
/* These will require a "tree" at runtime. */
- { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
+ { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
{ "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
'w', 0, 'p', 0, 'L',
NULL, NULL
},
- { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q", NULL,
+ { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+", NULL,
gcc_diag_flag_specs, gcc_diag_flag_pairs,
FMT_FLAG_ARG_CONVERT,
0, 0, 'p', 0, 'L',
NULL, &integer_type_node
},
- { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q", NULL,
+ { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+", NULL,
+ gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs,
+ FMT_FLAG_ARG_CONVERT,
+ 0, 0, 'p', 0, 'L',
+ NULL, &integer_type_node
+ },
+ { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+", NULL,
gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
FMT_FLAG_ARG_CONVERT,
0, 0, 'p', 0, 'L',
break;
}
if (args != 0)
- warning (0, "function might be possible candidate for %qs format attribute",
+ warning (OPT_Wattributes, "function might be possible "
+ "candidate for %qs format attribute",
format_types[info.format_type].name);
}
}
{
if (dollar_needed)
{
- warning (0, "missing $ operand number in format");
+ warning (OPT_Wformat, "missing $ operand number in format");
return -1;
}
else
{
if (dollar_needed)
{
- warning (0, "missing $ operand number in format");
+ warning (OPT_Wformat, "missing $ operand number in format");
return -1;
}
else
*format = fcp + 1;
if (pedantic && !dollar_format_warned)
{
- warning (0, "%s does not support %%n$ operand number formats",
+ warning (OPT_Wformat, "%s does not support %%n$ operand number formats",
C_STD_NAME (STD_EXT));
dollar_format_warned = 1;
}
if (overflow_flag || argnum == 0
|| (dollar_first_arg_num && argnum > dollar_arguments_count))
{
- warning (0, "operand number out of range in format");
+ warning (OPT_Wformat, "operand number out of range in format");
return -1;
}
if (argnum > dollar_max_arg_used)
&& dollar_arguments_used[argnum - 1] == 1)
{
dollar_arguments_used[argnum - 1] = 2;
- warning (0, "format argument %d used more than once in %s format",
+ warning (OPT_Wformat, "format argument %d used more than once in %s format",
argnum, fki->name);
}
else
format++;
if (*format == '$')
{
- warning (0, "$ operand number used after format without operand number");
+ warning (OPT_Wformat, "$ operand number used after format without operand number");
return true;
}
return false;
|| dollar_arguments_pointer_p[i]))
found_pointer_gap = true;
else
- warning (0, "format argument %d unused before used argument %d in $-style format",
+ warning (OPT_Wformat,
+ "format argument %d unused before used argument %d in $-style format",
i + 1, dollar_max_arg_used);
}
}
{
/* For strftime-like formats, warn for not checking the format
string; but there are no arguments to check. */
- if (warn_format_nonliteral)
- warning (0, "format not a string literal, format string not checked");
+ warning (OPT_Wformat_nonliteral,
+ "format not a string literal, format string not checked");
}
else if (info->first_arg_num != 0)
{
params = TREE_CHAIN (params);
++arg_num;
}
- if (params == 0 && (warn_format_nonliteral || warn_format_security))
- warning (0, "format not a string literal and no format arguments");
- else if (warn_format_nonliteral)
- warning (0, "format not a string literal, argument types not checked");
+ if (params == 0 && warn_format_security)
+ warning (OPT_Wformat_security,
+ "format not a string literal and no format arguments");
+ else if (params == 0 && warn_format_nonliteral)
+ warning (OPT_Wformat_nonliteral,
+ "format not a string literal and no format arguments");
+ else
+ warning (OPT_Wformat_nonliteral,
+ "format not a string literal, argument types not checked");
}
}
If the format is an empty string, this should be counted similarly to the
case of extra format arguments. */
if (res.number_extra_args > 0 && res.number_non_literal == 0
- && res.number_other == 0 && warn_format_extra_args)
- warning (0, "too many arguments for format");
+ && res.number_other == 0)
+ warning (OPT_Wformat_extra_args, "too many arguments for format");
if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
- && res.number_other == 0 && warn_format_extra_args)
- warning (0, "unused arguments in $-style format");
+ && res.number_other == 0)
+ warning (OPT_Wformat_extra_args, "unused arguments in $-style format");
if (res.number_empty > 0 && res.number_non_literal == 0
- && res.number_other == 0 && warn_format_zero_length)
- warning (0, "zero-length %s format string",
+ && res.number_other == 0)
+ warning (OPT_Wformat_zero_length, "zero-length %s format string",
format_types[info->format_type].name);
if (res.number_wide > 0)
- warning (0, "format is a wide character string");
+ warning (OPT_Wformat, "format is a wide character string");
if (res.number_unterminated > 0)
- warning (0, "unterminated format string");
+ warning (OPT_Wformat, "unterminated format string");
}
/* Callback from check_function_arguments_recurse to check a
return;
}
format_tree = TREE_OPERAND (format_tree, 0);
+ if (TREE_CODE (format_tree) == ARRAY_REF
+ && host_integerp (TREE_OPERAND (format_tree, 1), 0)
+ && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0)
+ format_tree = TREE_OPERAND (format_tree, 0);
if (TREE_CODE (format_tree) == VAR_DECL
&& TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
&& (array_init = decl_constant_value (format_tree)) != format_tree
if (*format_chars == 0)
{
if (format_chars - orig_format_chars != format_length)
- warning (0, "embedded %<\\0%> in format");
+ warning (OPT_Wformat, "embedded %<\\0%> in format");
if (info->first_arg_num != 0 && params != 0
&& has_operand_number <= 0)
{
continue;
if (*format_chars == 0)
{
- warning (0, "spurious trailing %<%%%> in format");
+ warning (OPT_Wformat, "spurious trailing %<%%%> in format");
continue;
}
if (*format_chars == '%')
*format_chars, NULL);
if (strchr (flag_chars, *format_chars) != 0)
{
- warning (0, "repeated %s in format", _(s->name));
+ warning (OPT_Wformat, "repeated %s in format", _(s->name));
}
else
{
++format_chars;
if (*format_chars == 0)
{
- warning (0, "missing fill character at end of strfmon format");
+ warning (OPT_Wformat, "missing fill character at end of strfmon format");
return;
}
}
{
if (params == 0)
{
- warning (0, "too few arguments for format");
+ warning (OPT_Wformat, "too few arguments for format");
return;
}
cur_param = TREE_VALUE (params);
}
if (found_width && !non_zero_width_char &&
(fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
- warning (0, "zero width in %s format", fki->name);
+ warning (OPT_Wformat, "zero width in %s format", fki->name);
if (found_width)
{
i = strlen (flag_chars);
flag_chars[i++] = fki->left_precision_char;
flag_chars[i] = 0;
if (!ISDIGIT (*format_chars))
- warning (0, "empty left precision in %s format", fki->name);
+ warning (OPT_Wformat, "empty left precision in %s format", fki->name);
while (ISDIGIT (*format_chars))
++format_chars;
}
{
if (params == 0)
{
- warning (0, "too few arguments for format");
+ warning (OPT_Wformat, "too few arguments for format");
return;
}
cur_param = TREE_VALUE (params);
{
if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
&& !ISDIGIT (*format_chars))
- warning (0, "empty precision in %s format", fki->name);
+ warning (OPT_Wformat, "empty precision in %s format", fki->name);
while (ISDIGIT (*format_chars))
++format_chars;
}
{
/* Warn if the length modifier is non-standard. */
if (ADJ_STD (length_chars_std) > C_STD_VER)
- warning (0, "%s does not support the %qs %s length modifier",
+ warning (OPT_Wformat,
+ "%s does not support the %qs %s length modifier",
C_STD_NAME (length_chars_std), length_chars,
fki->name);
}
{
const format_flag_spec *s = get_flag_spec (flag_specs,
*format_chars, NULL);
- warning (0, "repeated %s in format", _(s->name));
+ warning (OPT_Wformat, "repeated %s in format", _(s->name));
}
else
{
|| (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
&& format_char == '%'))
{
- warning (0, "conversion lacks type at end of format");
+ warning (OPT_Wformat, "conversion lacks type at end of format");
continue;
}
format_chars++;
if (fci->format_chars == 0)
{
if (ISGRAPH (format_char))
- warning (0, "unknown conversion type character %qc in format",
+ warning (OPT_Wformat, "unknown conversion type character %qc in format",
format_char);
else
- warning (0, "unknown conversion type character 0x%x in format",
+ warning (OPT_Wformat, "unknown conversion type character 0x%x in format",
format_char);
continue;
}
if (pedantic)
{
if (ADJ_STD (fci->std) > C_STD_VER)
- warning (0, "%s does not support the %<%%%c%> %s format",
+ warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format",
C_STD_NAME (fci->std), format_char, fki->name);
}
continue;
if (strchr (fci->flag_chars, flag_chars[i]) == 0)
{
- warning (0, "%s used with %<%%%c%> %s format",
+ warning (OPT_Wformat, "%s used with %<%%%c%> %s format",
_(s->name), format_char, fki->name);
d++;
continue;
{
const format_flag_spec *t;
if (ADJ_STD (s->std) > C_STD_VER)
- warning (0, "%s does not support %s",
+ warning (OPT_Wformat, "%s does not support %s",
C_STD_NAME (s->std), _(s->long_name));
t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
? t->long_name
: s->long_name);
if (ADJ_STD (t->std) > C_STD_VER)
- warning (0, "%s does not support %s with the %<%%%c%> %s format",
+ warning (OPT_Wformat,
+ "%s does not support %s with the %<%%%c%> %s format",
C_STD_NAME (t->std), _(long_name),
format_char, fki->name);
}
if (bad_flag_pairs[i].ignored)
{
if (bad_flag_pairs[i].predicate != 0)
- warning (0, "%s ignored with %s and %<%%%c%> %s format",
+ warning (OPT_Wformat,
+ "%s ignored with %s and %<%%%c%> %s format",
_(s->name), _(t->name), format_char,
fki->name);
else
- warning (0, "%s ignored with %s in %s format",
+ warning (OPT_Wformat, "%s ignored with %s in %s format",
_(s->name), _(t->name), fki->name);
}
else
{
if (bad_flag_pairs[i].predicate != 0)
- warning (0, "use of %s and %s together with %<%%%c%> %s format",
+ warning (OPT_Wformat,
+ "use of %s and %s together with %<%%%c%> %s format",
_(s->name), _(t->name), format_char,
fki->name);
else
- warning (0, "use of %s and %s together in %s format",
+ warning (OPT_Wformat, "use of %s and %s together in %s format",
_(s->name), _(t->name), fki->name);
}
}
else if (strchr (fci->flags2, '2') != 0)
y2k_level = 2;
if (y2k_level == 3)
- warning (0, "%<%%%c%> yields only last 2 digits of year in some locales",
- format_char);
+ warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
+ "year in some locales", format_char);
else if (y2k_level == 2)
- warning (0, "%<%%%c%> yields only last 2 digits of year", format_char);
+ warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
+ "year", format_char);
}
if (strchr (fci->flags2, '[') != 0)
++format_chars;
if (*format_chars != ']')
/* The end of the format string was reached. */
- warning (0, "no closing %<]%> for %<%%[%> format");
+ warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format");
}
wanted_type = 0;
wanted_type_std = fci->types[length_chars_val].std;
if (wanted_type == 0)
{
- warning (0, "use of %qs length modifier with %qc type character",
+ warning (OPT_Wformat,
+ "use of %qs length modifier with %qc type character",
length_chars, format_char);
/* Heuristic: skip one argument when an invalid length/type
combination is encountered. */
arg_num++;
if (params == 0)
{
- warning (0, "too few arguments for format");
+ warning (OPT_Wformat, "too few arguments for format");
return;
}
params = TREE_CHAIN (params);
&& ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
{
if (ADJ_STD (wanted_type_std) > C_STD_VER)
- warning (0, "%s does not support the %<%%%s%c%> %s format",
+ warning (OPT_Wformat,
+ "%s does not support the %<%%%s%c%> %s format",
C_STD_NAME (wanted_type_std), length_chars,
format_char, fki->name);
}
if (main_arg_num != 0)
{
if (suppressed)
- warning (0, "operand number specified with suppressed assignment");
+ warning (OPT_Wformat, "operand number specified with "
+ "suppressed assignment");
else
- warning (0, "operand number specified for format taking no argument");
+ warning (OPT_Wformat, "operand number specified for format "
+ "taking no argument");
}
}
else
++arg_num;
if (has_operand_number > 0)
{
- warning (0, "missing $ operand number in format");
+ warning (OPT_Wformat, "missing $ operand number in format");
return;
}
else
{
if (params == 0)
{
- warning (0, "too few arguments for format");
+ warning (OPT_Wformat, "too few arguments for format");
return;
}
&& i == 0
&& cur_param != 0
&& integer_zerop (cur_param))
- warning (0, "writing through null pointer (argument %d)",
- arg_num);
+ warning (OPT_Wformat, "writing through null pointer "
+ "(argument %d)", arg_num);
/* Check for reading through a NULL pointer. */
if (types->reading_from_flag
&& i == 0
&& cur_param != 0
&& integer_zerop (cur_param))
- warning (0, "reading through null pointer (argument %d)",
- arg_num);
+ warning (OPT_Wformat, "reading through null pointer "
+ "(argument %d)", arg_num);
if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
cur_param = TREE_OPERAND (cur_param, 0);
&& (CONSTANT_CLASS_P (cur_param)
|| (DECL_P (cur_param)
&& TREE_READONLY (cur_param))))))
- warning (0, "writing into constant object (argument %d)",
- arg_num);
+ warning (OPT_Wformat, "writing into constant object "
+ "(argument %d)", arg_num);
/* If there are extra type qualifiers beyond the first
indirection, then this makes the types technically
&& (TYPE_READONLY (cur_type)
|| TYPE_VOLATILE (cur_type)
|| TYPE_RESTRICT (cur_type)))
- warning (0, "extra type qualifiers in format argument "
- "(argument %d)",
+ warning (OPT_Wformat, "extra type qualifiers in format "
+ "argument (argument %d)",
arg_num);
}
if (wanted_type_name)
{
if (descr)
- warning (0, "%s should have type %<%s%s%>, but argument %d has type %qT",
+ warning (OPT_Wformat, "%s should have type %<%s%s%>, "
+ "but argument %d has type %qT",
descr, wanted_type_name, p, arg_num, arg_type);
else
- warning (0, "format %q.*s expects type %<%s%s%>, but argument %d has type %qT",
+ warning (OPT_Wformat, "format %q.*s expects type %<%s%s%>, "
+ "but argument %d has type %qT",
format_length, format_start, wanted_type_name, p,
arg_num, arg_type);
}
else
{
if (descr)
- warning (0, "%s should have type %<%T%s%>, but argument %d has type %qT",
+ warning (OPT_Wformat, "%s should have type %<%T%s%>, "
+ "but argument %d has type %qT",
descr, wanted_type, p, arg_num, arg_type);
else
- warning (0, "format %q.*s expects type %<%T%s%>, but argument %d has type %qT",
+ warning (OPT_Wformat, "format %q.*s expects type %<%T%s%>, "
+ "but argument %d has type %qT",
format_length, format_start, wanted_type, p, arg_num, arg_type);
}
}
if (!loc || !t || !hwi)
{
- static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci;
+ static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci;
static format_length_info *diag_ls;
unsigned int i;
/* All the GCC diag formats use the same length specs. */
if (!diag_ls)
dynamic_format_types[gcc_diag_format_type].length_char_specs =
+ dynamic_format_types[gcc_tdiag_format_type].length_char_specs =
dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
diag_ls = (format_length_info *)
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 (loc)
+ {
+ i = find_char_info_specifier_index (tdiag_fci, 'H');
+ tdiag_fci[i].types[0].type = &loc;
+ tdiag_fci[i].pointer_count = 1;
+ }
+ 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, 'J');
+ 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 =
initialize certain bits a runtime. */
if (info.format_type == asm_fprintf_format_type
|| info.format_type == gcc_diag_format_type
+ || info.format_type == gcc_tdiag_format_type
|| info.format_type == gcc_cdiag_format_type
|| info.format_type == gcc_cxxdiag_format_type)
{
/* If this is one of the diagnostic attributes, then we have to
initialize 'location_t' and 'tree' at runtime. */
else if (info.format_type == gcc_diag_format_type
+ || info.format_type == gcc_tdiag_format_type
|| info.format_type == gcc_cdiag_format_type
|| info.format_type == gcc_cxxdiag_format_type)
init_dynamic_diag_info ();