This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: add "%J" for diagnostics (Redux. Positional format specifierfor diagnostic)
Gabriel Dos Reis wrote:
Richard Henderson <rth@redhat.com> writes:
| On Tue, Sep 23, 2003 at 06:58:33PM +0200, Gabriel Dos Reis wrote:
| > %H can appear anywhere in the text. If it is at the begining then it
| > indicates the prefix, otherwise it is handled as I inidicated, just
| > like any regular format specifier.
|
| Then why do we do this?
|
| /* Skip any leading text. */
| for (p = text->format_spec; *p && *p != '%'; ++p)
| ;
we should not have it. It mush have been a copy-n-paste error. Thanks,
I am attaching the diff for positional parameter support including "%J"
hopefully.
As the preceding disucssion has revealed,
the handling of "%H" was a little fishy BEFORE
my patch, too. We can try a format string "... %H ..." that contains %H
in the middle of it, and the output looks a little out of place although
I kept the output format as is. (No one uses %H in the middle of a format
string anyway.)
In the presence of the positional format specifiers,
the first %H must be written as %$1H and
so the handling needs to take care of it.
Patch attached.
--
int main(void){int j=2003;/*(c)2003 cishikawa. */
char t[] ="<CI> @abcdefghijklmnopqrstuvwxyz.,\n\"";
char *i ="g>qtCIuqivb,gCwe\np@.ietCIuqi\"tqkvv is>dnamz";
while(*i)((j+=strchr(t,*i++)-(int)t),(j%=sizeof t-1),
(putchar(t[j])));return 0;}/* under GPL */
ChangeLog
2003-09-23 <ishikawa@yk.rim.or.jp>
Positional format specifier support for
pp_format_text().
* pretty-print.h (struct): struct argtype_t, enum
arg_decode_action, struct text_info.
printer_fn takes extra argument of type arg_decode_action.
* pretty-print.c (pp_helper_abort): print the problematic format string
and abort.
(pp_type_width): returns the argument width based
on format specifier type.
(pp_compatible_and_has_same_width): check if the double use of
an argument uses the same type and width.
(set_argument_type_with_precision): store the argument type in
a static array.
(set_argument_type): store the argument type without precision.
(pp_integer_with_precision_NEW): Macro based on the
original pp_integer_with_precision. Uses the created argument
array to fetch the value.
(pp_build_argument_array): build an array of argument to support
positional format specifier.
(pp_format_text): modified to work with the positional format
specifier support. %H no longer prints output.
* c-objc-common.c (c_tree_printer): takes extra argument of type
arg_decode_action. Modified to support four actions.
* toplev.c (default_tree_printer): ditto.
* cp/error.c (cp_printer) : ditto
* diagnostic.c (text_specifies_location):
check for "%1$H" as well as for "%H". Restores the pointer.
'%H' is now retained by text_specifies_location.
Similar handling for the newly introduced '%J'.
diagnostic_J_tree2locus() added.
cp/ChangeLog
2003-09-18 <ishikawa@yk.rim.or.jp>
Positional format specifier support for
pp_format_text().
* error.c (cp_printer): takes extra argument of type
arg_decode_action. Modified to support four actions.
Index: gcc/c-objc-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.35
diff -c -3 -p -r1.35 c-objc-common.c
*** gcc/c-objc-common.c 21 Sep 2003 05:07:09 -0000 1.35
--- gcc/c-objc-common.c 23 Sep 2003 18:11:27 -0000
*************** Software Foundation, 59 Temple Place - S
*** 39,45 ****
#include "target.h"
#include "cgraph.h"
! static bool c_tree_printer (pretty_printer *, text_info *);
static tree start_cdtor (int);
static void finish_cdtor (tree);
--- 39,45 ----
#include "target.h"
#include "cgraph.h"
! static bool c_tree_printer (pretty_printer *, text_info *, arg_decode_action);
static tree start_cdtor (int);
static void finish_cdtor (tree);
*************** c_objc_common_finish_file (void)
*** 288,321 ****
These format specifiers form a subset of the format specifiers set used
by the C++ front-end.
Please notice when called, the `%' part was already skipped by the
! diagnostic machinery. */
static bool
! c_tree_printer (pretty_printer *pp, text_info *text)
{
! tree t = va_arg (*text->args_ptr, tree);
! switch (*text->format_spec)
{
- case 'D':
- case 'F':
- case 'T':
- {
- const char *n = DECL_NAME (t)
- ? (*lang_hooks.decl_printable_name) (t, 2)
- : "({anonymous})";
- pp_string (pp, n);
- }
- return true;
! case 'E':
! if (TREE_CODE (t) == IDENTIFIER_NODE)
! {
! pp_string (pp, IDENTIFIER_POINTER (t));
! return true;
! }
! return false;
! default:
! return false;
}
}
--- 288,396 ----
These format specifiers form a subset of the format specifiers set used
by the C++ front-end.
Please notice when called, the `%' part was already skipped by the
! diagnostic machinery.
!
!
! Additional comment about support for positional parameters.
!
! Modifying c_tree_printer to support positional parameters was
! relatively easy.
! Reasons why.
!
! (1) Only a single format character is used as opposed to
! multi-character sequence.
!
! (2) Value fetched from the argument list is of only ONE type, namely
! "tree".
!
! Below, I play fast and loose in handling of 'E' format.
! I don't return "false" to indicate error until
! PRINT_ARG_VALUE is requested, and the TREE value is not
! found to be IDENTIFIER_NODE.
! This is because I know for certain that the any error is
! eventually caught during the processing of PRINT_ARG_VALUE.
! No need to complicate processing during
! - GET_ARG_TYPE, and
! - COPY_ARG_VALUE. */
static bool
! c_tree_printer (pretty_printer *pp, text_info *text, arg_decode_action a)
{
! tree t;
!
! if (a == PRINT_ARG_VALUE_AS_BEFORE
! || a == PRINT_ARG_VALUE)
! {
! if (a == PRINT_ARG_VALUE)
! t = (tree) text->arg_array[text->index_num].v.ptr;
! else
! t = va_arg (*text->args_ptr, tree);
!
! switch (*text->format_spec)
! {
! case 'D':
! case 'F':
! case 'T':
! {
! const char *n = DECL_NAME (t)
! ? (*lang_hooks.decl_printable_name) (t, 2)
! : "({anonymous})";
! pp_string (pp, n);
! }
! return true;
!
! case 'E':
! if (TREE_CODE (t) == IDENTIFIER_NODE)
! {
! pp_string (pp, IDENTIFIER_POINTER (t));
! return true;
! }
! return false;
!
! default:
! return false;
! }
! }
! else if (a == GET_ARG_TYPE)
{
! text->bump_format = 0;
! switch (*text->format_after_percent_or_dollar)
! {
! case 'D':
! case 'F':
! case 'T':
! case 'E':
! text->bump_format = 1;
! text->arg_array[text->index_num].custom_format[0]
! = *text->format_after_percent_or_dollar;
! return true;
! default:
! return false;
! }
! }
! else if (a == COPY_ARG_VALUE)
! {
!
! text->arg_array[text->index_num].v.ptr
! = (void *) va_arg (*text->args_ptr, tree);
! text->bump_format = 1; /* we know it is 1 at most. */
! switch (*text->format_after_percent_or_dollar)
! {
! case 'D':
! case 'F':
! case 'T':
! return true;
!
! case 'E':
! return true;
! default:
! return false;
! }
}
+ else
+ abort ();
+
+ return false;
}
Index: gcc/diagnostic.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.c,v
retrieving revision 1.133
diff -c -3 -p -r1.133 diagnostic.c
*** gcc/diagnostic.c 22 Sep 2003 05:09:12 -0000 1.133
--- gcc/diagnostic.c 23 Sep 2003 18:11:28 -0000
*************** diagnostic_initialize (diagnostic_contex
*** 118,126 ****
context->x_data = NULL;
}
/* Returns true if the next format specifier in TEXT is a format specifier
for a location_t. If so, update the object pointed by LOCUS to reflect
! the specified location in *TEXT->args_ptr. */
static bool
text_specifies_location (text_info *text, location_t *locus)
{
--- 118,144 ----
context->x_data = NULL;
}
+ /* Returns location_t struct from a tree node for a
+ declaration. Called from within pretty-print.c.
+ This function is here so that pretty-print.c itself is
+ free of tree-related typedefs, etc. necessary for DECL_SOURCE_LOCATION. */
+ location_t
+ diagnostic_J_tree2locus (tree t)
+ {
+ return DECL_SOURCE_LOCATION (t);
+ }
+
/* Returns true if the next format specifier in TEXT is a format specifier
for a location_t. If so, update the object pointed by LOCUS to reflect
! the specified location in *TEXT->args_ptr.
!
! To bring consistency to positional format specifier support,
! we restore the original args_ptr before returning
! so that the subsequent call to pp_text_format() can access %H (or %1$H).
! and we don't remove the %H reference.
!
! pp_format_text() doesn't formats/prints the first %H reference.
! It merely bumps the arg pointer. */
static bool
text_specifies_location (text_info *text, location_t *locus)
{
*************** text_specifies_location (text_info *text
*** 129,152 ****
for (p = text->format_spec; *p && *p != '%'; ++p)
;
! /* Extract the location information if any. */
! if (p[0] == '%' && p[1] == 'H')
{
*locus = *va_arg (*text->args_ptr, location_t *);
! text->format_spec = p + 2;
return true;
}
! else if (p[0] == '%' && p[1] == 'J')
{
tree t = va_arg (*text->args_ptr, tree);
*locus = DECL_SOURCE_LOCATION (t);
! text->format_spec = p + 2;
return true;
}
return false;
}
void
diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
va_list *args, location_t location,
--- 147,181 ----
for (p = text->format_spec; *p && *p != '%'; ++p)
;
! /* assert *p == NUL
! || *p == '%' */
!
! /* Extract the location information if any.
! We now match either %H or %1$H, and
! don't skip in the format_spec either. */
!
! if (strncmp (p, "%H", 2) == 0
! || strncmp (p, "%1$H", 4) == 0)
{
+ va_list saved_ptr = *text->args_ptr; /* save */
*locus = *va_arg (*text->args_ptr, location_t *);
! *text->args_ptr = saved_ptr; /* restore */
return true;
}
! else if ( strncmp (p, "%J", 2) == 0
! || strncmp (p, "%1$J", 4) == 0 )
{
+ va_list saved_ptr = *text->args_ptr; /* save */
tree t = va_arg (*text->args_ptr, tree);
*locus = DECL_SOURCE_LOCATION (t);
! *text->args_ptr = saved_ptr; /* restore */
return true;
}
return false;
}
+
void
diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
va_list *args, location_t location,
*************** fnotice (FILE *file, const char *msgid,
*** 562,568 ****
so give up now. But do try to flush out the previous error.
This mustn't use internal_error, that will cause infinite recursion. */
! static void
error_recursion (diagnostic_context *context)
{
if (context->lock < 3)
--- 591,597 ----
so give up now. But do try to flush out the previous error.
This mustn't use internal_error, that will cause infinite recursion. */
! void
error_recursion (diagnostic_context *context)
{
if (context->lock < 3)
Index: gcc/diagnostic.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.h,v
retrieving revision 1.66
diff -c -3 -p -r1.66 diagnostic.h
*** gcc/diagnostic.h 22 Aug 2003 06:25:08 -0000 1.66
--- gcc/diagnostic.h 23 Sep 2003 18:11:28 -0000
*************** extern char *diagnostic_build_prefix (di
*** 182,185 ****
--- 182,189 ----
extern void verbatim (const char *, ...);
extern char *file_name_as_prefix (const char *);
+ extern location_t diagnostic_J_tree2locus (tree t);
+
+
+
#endif /* ! GCC_DIAGNOSTIC_H */
Index: gcc/pretty-print.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.c,v
retrieving revision 2.6
diff -c -3 -p -r2.6 pretty-print.c
*** gcc/pretty-print.c 12 Sep 2003 23:47:01 -0000 2.6
--- gcc/pretty-print.c 23 Sep 2003 18:11:30 -0000
*************** Software Foundation, 59 Temple Place - S
*** 26,31 ****
--- 26,33 ----
#include "coretypes.h"
#include "pretty-print.h"
+ #include <ctype.h>
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
*************** Software Foundation, 59 Temple Place - S
*** 58,63 ****
--- 60,67 ----
while (0)
+
+
/* Subroutine of pp_set_maximum_length. Set up PRETTY-PRINTER's
internal maximum characters per line. */
static void
*************** pp_base_indent (pretty_printer *pp)
*** 164,169 ****
--- 168,787 ----
pp_space (pp);
}
+
+ /* ========================================
+ Supporting positional format specifiers a la
+ %2$d, %1$d, %3$c, etc..
+ ======================================== */
+ #define UNDEFINED_FORMAT 0
+ #define LOCATION_T_TYPE 1001
+ #define LOCATION_D_TYPE 1002 /* for DECL_SOURCE_LOCATION, %J */
+
+ /* Aborting with error message and the format string that caused it. */
+ static void pp_helper_abort (const char *a, text_info *text)
+ {
+ fprintf (stderr, "Problem with output formatting: %s\n", a);
+ fprintf (stderr, "format=<<%s>>\n", text->original_format_spec);
+ #ifdef ENABLE_CHECKING
+ abort ();
+ #endif
+ }
+
+ /* type compatibility info for %d$c processing.
+ Check is based only on the width, i.e., sizeof (t).
+
+ The whole scheme does not feel quit right in that
+ it is not quite clear whether %lld, %ld, and/or %d should
+ be compatible with HOST_WIDE_INT.
+ But it works. */
+ static int pp_type_width (int t)
+ {
+ switch (t)
+ {
+ default:
+ fprintf (stderr, "pp_type_width: unknown type spec. %d\n", t);
+ abort ();
+ break;
+
+ case 's': return sizeof (char *);
+
+ case 'c': return sizeof (int);
+
+ case 'i':
+ case 'd': return sizeof (int);
+
+ /* HOST_WIDE_INT may be blank "" on some systems such as x86
+ So we use 'W' to stand for it. */
+ case 'W' /* for HOST_WIDE_INT */ : return sizeof (long);
+
+ case 'U' /* UNSIGNED_HOST_WIDE_INT */ : return sizeof (unsigned long int);
+
+ case 'x':
+ case 'u':
+ case 'o': return sizeof (unsigned int) ;
+
+ case 'p': return sizeof (void *);
+
+ case LOCATION_D_TYPE: return sizeof (void *);
+
+ case LOCATION_T_TYPE: return sizeof (void *);
+ }
+
+ /* NOTREACHED */
+ abort ();
+ }
+
+ /* if an argument is referenced twice, we
+ say, the references are compatible if the type (width)
+ is the same, and its precisions are the same.
+
+ E.g. %1$d and %1$lld is not considered compatible. */
+ static int
+ pp_compatible_and_has_same_width (int t, int prec1, int u, int prec2)
+ {
+ return pp_type_width (t) == pp_type_width (u)
+ && prec1 == prec2 ;
+ }
+
+
+ /* store argument tye with precision. */
+ static void
+ set_argument_type_with_precision (int i, int type,
+ int precision, text_info *text)
+ {
+ if (i <= 0 || i >= 10)
+ abort ();
+
+ if (precision < 0 || precision > 2)
+ abort ();
+
+ if (type == UNDEFINED_FORMAT)
+ abort ();
+
+ /* First definition/reference is OK. */
+ if (text->arg_array[i].typespec == UNDEFINED_FORMAT)
+ {
+ text->arg_array[i].typespec = type;
+ text->arg_array[i].precision = precision;
+
+ switch (precision)
+ {
+ default: abort ();
+
+ case 0:
+ text->arg_array[i].format[0] = '%';
+ text->arg_array[i].format[1] = type;
+ break;
+
+ case 1:
+ text->arg_array[i].format[0] = '%';
+ text->arg_array[i].format[1] = 'l';
+ text->arg_array[i].format[2] = type;
+ break;
+
+ case 2:
+ text->arg_array[i].format[0] = '%';
+ text->arg_array[i].format[1] = 'l';
+ text->arg_array[i].format[2] = 'l';
+ text->arg_array[i].format[3] = type;
+ break;
+ }
+
+ return;
+ }
+
+ /* Check the double definition */
+ if (pp_compatible_and_has_same_width
+ (text->arg_array[i].typespec, text->arg_array[i].precision,
+ type, precision))
+ return;
+ else
+ {
+ fprintf (stderr, "pretty-print.c: Specifying incompatible types for argument (at %d) twice\n", i);
+ fprintf (stderr, "format : <<%s>>\n", text->arg_array[0].v.cptr);
+ #ifdef ENABLE_CHECKING
+ abort ();
+ #endif
+ }
+ }
+
+ /* store argument type (without precision.) */
+ static void
+ set_argument_type (int i, int type, text_info *text)
+ {
+ /* precision is 0 */
+ set_argument_type_with_precision (i, type, 0, text);
+ }
+
+
+ /* we define the format string to be used
+ at the time of first scan (for types)
+ by calling set_argument_type_with_precision,
+ and do away with the dynamic construction of "%" F, "%l", F, "%ll", F
+ in pp_integer_with_precision.
+
+ Assumption. This is used ONLY for
+ 'd', 'i', 'x', 'o', 'u', that is for value meant to be numbers.
+ So I use i, li, and lli fields.
+ CAVEAT: I am making an assumption that
+ long long int, and long long unsigned uses a same size
+ memory cell. This seems reasonable.
+
+ arg_array[ind] holds the value, format, and precision. */
+
+
+ #define pp_integer_with_precision_NEW(PP, ind, text) \
+ do \
+ switch (text->arg_array[ind].precision) \
+ { \
+ case 0: \
+ pp_scalar \
+ (PP, text->arg_array[ind].format, text->arg_array[ind].v.i); \
+ break; \
+ \
+ case 1: \
+ pp_scalar \
+ (PP, text->arg_array[ind].format, text->arg_array[ind].v.l); \
+ break; \
+ \
+ case 2: \
+ pp_scalar \
+ (PP, text->arg_array[ind].format, text->arg_array[ind].v.ll); \
+ break; \
+ \
+ default: \
+ abort (); break; \
+ } \
+ while (0)
+
+
+ /* Build argument array to support format specifiers in the form
+ of %1$s, %2$d %3$d, etc. */
+ static void
+ pp_build_argument_array (const char * format,
+ pretty_printer *pp, text_info *text)
+ {
+ int arg_index = 0;
+ int i;
+ int has_seen_number = 0; /* have we seen "n$" in %n$d? */
+
+ text->arg_max = 0;
+
+ memset (text->arg_array,
+ 0, sizeof (text->arg_array)); /* fill in zero. UNDEFINED_FORMAT. */
+
+ text->arg_array[0].v.cptr = (char *) format; /* record for error message. */
+
+ /* loop through the string just looking for the type
+ Note that the variable, format, changes its value in this loop. */
+ for (; *format; ++format)
+ {
+ int precision = 0;
+ bool wide = false;
+
+ has_seen_number = 0;
+
+ /* "Ignore text." while we build the array. */
+ {
+ const char *p = format;
+ while (*p && *p != '%')
+ ++p;
+ format = p;
+ }
+
+ /* assert: format == '\0'
+ || format == '%'
+ */
+
+ if (*format == '\0') /* we are at the end. Finish */
+ break;
+
+ /* We got a '%'. Parse precision modifiers, if any.
+ We also need to handle [0-9] as in %1$d */
+
+ /* assert:
+ we have % [non-digit]
+ || we have % [digit] $ */
+
+ if (isdigit (format[1]))
+ {
+ /* %1$ ... */
+ if (format[2] == '$')
+ {
+ char tmp[2];
+
+ tmp[1] = '\0';
+ tmp[0] = format[1];
+ arg_index = atoi (tmp);
+
+ if (arg_index == 0)
+ {
+ pp_helper_abort ("The digit that comes after % must be non-zero.", text);
+ }
+
+ if (text->arg_max < arg_index)
+ text->arg_max = arg_index;
+
+ has_seen_number = 1;
+
+ format += 2;
+ }
+ else /* We expected '$' after "%1" */
+ {
+ if (isdigit (format[2]))
+ pp_helper_abort ("we handle only 1-9 in %%d$ as of now.\n", text);
+ else
+ pp_helper_abort ("We expected '$' after %% and digit as in '%%1$'", text);
+ }
+ }
+
+ /* assert:
+ format points at the % in % [non-digit]
+ || format points at the $ in % [digit] $ */
+
+ switch (*++format)
+ {
+ case 'w':
+ wide = true;
+ ++format;
+ break;
+
+ case 'l':
+ do
+ ++precision;
+ while (*++format == 'l');
+ break;
+
+
+ default:
+ break;
+ }
+
+ /* We don't support precision behond that of "long long". */
+ if (precision > 2)
+ pp_helper_abort ("We don't support precision behond that of \"long long\" ", text);
+
+ if (arg_index >= 10 || arg_index < 0)
+ abort ();
+
+ if (!has_seen_number && ! (*format == '%' || *format == 'm'))
+ {
+ pp_helper_abort ("Use %n$c form specifier in ALL places except for % (percent sign) and %m.", text);
+ }
+
+ switch (*format)
+ {
+ case 'c':
+ set_argument_type (arg_index, 'c', text);
+ break;
+
+ case 'd':
+ case 'i':
+ if (wide)
+ set_argument_type (arg_index, 'W' /* HOST_WIDE_INT*/, text);
+ else
+ set_argument_type_with_precision (arg_index, 'd', precision, text);
+ break;
+
+ /* TODO/FIXME long 'U', and long long 'U' can be
+ used as in %lw %llw ? */
+ case 'o':
+ if (wide)
+ set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text) ;
+ else
+ set_argument_type_with_precision (arg_index, 'o', precision, text);
+ break;
+
+ case 's':
+ set_argument_type (arg_index, 's', text); /* char *ptr */
+ break;
+
+ case 'p':
+ set_argument_type (arg_index, 'p', text); /* void *p */
+ break;
+
+ case 'u': /* now we must split this from 'x' to handle
+ precision string processing. */
+ if (wide)
+ set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text);
+ else
+ set_argument_type_with_precision (arg_index, 'u', precision, text);
+ break;
+
+
+ case 'x':
+ if (wide)
+ set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text);
+ else
+ set_argument_type_with_precision (arg_index, 'x', precision, text);
+ break;
+
+ case 'm': /* error code: handles separately. */
+ break;
+
+ case '%': /* % character */
+
+ if (format[-1] != '%')
+ {
+ /* Before we catch this, we saw subtle Error as in:
+ argument at 1 not specified in format string. <<pointer=%3$p, char=%1$%c, integer=%4$d
+
+ %1$%c is handled as if it were %%c and thus
+ no information about argument was recorded. */
+
+ fprintf (stderr, "cf. char=%%1$%%c is handled as if it were char %%%%c\n");
+ fprintf (stderr, "That is, 1$ is ignored when the second %% is seen.\n");
+
+ pp_helper_abort ("We should have a consecutive % s ", text);
+
+ }
+
+ break;
+
+ case 'J':
+ set_argument_type (arg_index, LOCATION_D_TYPE, text);
+ break;
+
+ case 'H':
+ set_argument_type (arg_index, LOCATION_T_TYPE, text);
+ break;
+
+ case '.': /* Either %.*s, orpositional paraeter as in
+ %1$.*3$s ... 1st argument with the
+ width given by the third argument. */
+ {
+ /* From SUS.
+ The precision takes the form of a period ( '.' ) followed
+ either by an asterisk ( '*' ), described below, or an
+ optional decimal digit string, where a null digit string is
+ treated as zero.
+
+ [...]
+
+ In format strings containing the "%n$" form of a
+ conversion specification, a field width or precision may
+ be indicated by the sequence "*m$", where m is a decimal
+ integer in the range [1,{NL_ARGMAX}] giving the position
+ in the argument list (after the format argument) of an
+ integer argument containing the field width or
+ precision, */
+
+
+ /* We handle no precision specifier except for string type
+ as in `%.*s'.
+ pp_build_argument_array () is called when positional
+ specifier of the form %n$ is used and
+ so the width also needs to be specified as *m$ ! */
+
+ if (*++format != '*')
+ pp_helper_abort ("We expected '*' after '.'", text);
+ else
+ { /* we handle only %d$.*m$s : we have seen "*". */
+ int a;
+ char tmp[2];
+ int c;
+ c = *++format;
+ if (!isdigit (c))
+ pp_helper_abort ("We expected a digit after '*'", text);
+ tmp[0] = c;
+ tmp[1] = '\0';
+ a = atoi (tmp);
+ if (a == 0)
+ pp_helper_abort ("The digit that comes after % must be non-zero.\n", text);
+ if (text->arg_max < a)
+ text->arg_max = a;
+ if (text->arg_max < arg_index)
+ text->arg_max = arg_index;
+
+ set_argument_type (a, 'd', text); /* host int */
+ set_argument_type (arg_index, 's', text);
+ }
+ }
+ break;
+
+ default:
+
+ /* Let us see if custom decoder installed can understand the
+ format character. Custom format_decoder examples are as
+ follows.
+ c_tree_printer in c-objc-common.c
+ cp_print in cp/error.c
+ default_tree_printer in toplev.c */
+
+
+ /* Set up for calling custom format decoder
+ with GET_ARG_TYPE action. */
+
+ text->index_num = arg_index;
+ text->format_after_percent_or_dollar = format;
+
+ /* Save previously seen format, if any, for checking
+ incompatible double references later. */
+ memcpy (text->arg_array[0].custom_format,
+ text->arg_array[arg_index].custom_format,
+ sizeof (text->arg_array[0].custom_format));
+
+ if (arg_index <= 0 || arg_index > 9)
+ pp_helper_abort ("arg_index out of range.", text);
+
+ if (!pp_format_decoder (pp)
+ || !(*pp_format_decoder (pp)) (pp, text, GET_ARG_TYPE))
+ {
+ /* Ugh. Error. */
+
+ /* Hmmm. The front-end failed to install a format translator
+ but called us with an unrecognized format. Or, maybe, the
+ translated string just contains an invalid format, or
+ has formats in the wrong order. Sorry. */
+ pp_helper_abort ("Unrecognized format.", text);
+ }
+
+ /* Check for double definition for custom-extended format
+ argument */
+
+ if (text->arg_array[0].custom_format[0] == '\0')
+ ; /* OK. It was the first reference. */
+ else
+ {
+ /* If the previously used type information `matches' with
+ the latest type information, then the double usage is OK.
+ Otherwise, it is an error.
+
+ Now the semantics of `match' is a little tricky to get right.
+ We probably need to ask the format decoder to decide
+ the compatibility of two different format strings.
+
+ As an initial implementation, we simply use the strncmp ()
+ against the two format strings. */
+
+ if (strncmp (text->arg_array[0].custom_format,
+ text->arg_array[arg_index].custom_format,
+ sizeof (text->arg_array[0].custom_format)) == 0)
+ ; /* OK */
+ else
+ {
+ fprintf (stderr, "Specifying incompatible types for argument (at %d)\n", arg_index);
+ fprintf (stderr, "format:<<%s>>\n", text->arg_array[0].v.cptr);
+ abort ();
+ }
+
+ }
+
+ /* adjust the format pointer by the number of
+ bytes understood by the custom decoder. */
+ if (text->bump_format > 1)
+ format += (text->bump_format - 1);
+
+ }
+
+ }
+
+
+ /* Now let us scan the argumet and fetch the value as specified by the type.
+ NOTE: we start at position 1. */
+
+ for (i = 1; i <= text->arg_max; i++)
+ {
+ switch (text->arg_array[i].typespec)
+ {
+ case UNDEFINED_FORMAT:
+ if (text->arg_array[i].custom_format[0] == '\0')
+ {
+ fprintf (stderr, "argument at %d not specified in format string. <<%s>>\n", i, text->arg_array[0].v.cptr);
+ abort ();
+ }
+ else /* handling custom extended format character */
+ {
+ /* setup for COPY_ARG_VALUE. */
+ text->index_num = i;
+ text->format_after_percent_or_dollar
+ = text->arg_array[i].custom_format;
+
+ if (!pp_format_decoder (pp)
+ || !(*pp_format_decoder (pp)) (pp, text,
+ COPY_ARG_VALUE))
+ {
+ pp_helper_abort ("Unrecognized format.", text);
+ }
+ }
+
+ break;
+
+ case 's': text->arg_array[i].v.cptr = (char *) va_arg (*text->args_ptr, const char *);
+ break;
+
+ case 'i':
+ case 'd':
+ switch (text->arg_array[i].precision)
+ {
+ case 0:
+ text->arg_array[i].v.i = va_arg (*text->args_ptr, int);
+ break;
+ case 1:
+ text->arg_array[i].v.l = va_arg (*text->args_ptr, long int);
+ break;
+ case 2:
+ text->arg_array[i].v.ll = va_arg (*text->args_ptr, long long int);
+ break;
+
+ default: abort ();
+ }
+ break;
+
+ case 'c': text->arg_array[i].v.i = va_arg (*text->args_ptr, int);
+ break;
+
+
+ case 'W' /* We use 'W' for HOST_WIDE_INT */ :
+ text->arg_array[i].v.hwi = va_arg (*text->args_ptr, HOST_WIDE_INT);
+ break;
+
+ case 'U' : /* We use 'U' for UNSIGNED_HOST_WIDE_INT*/
+ text->arg_array[i].v.uhwi = va_arg (*text->args_ptr, unsigned HOST_WIDE_INT);
+ break;
+
+ case 'x':
+ case 'u':
+ case 'o':
+ switch (text->arg_array[i].precision)
+ {
+ case 0:
+ text->arg_array[i].v.ui = va_arg (*text->args_ptr, unsigned);
+ break;
+ case 1:
+ text->arg_array[i].v.ul = va_arg (*text->args_ptr, long unsigned);
+ break;
+ case 2:
+ text->arg_array[i].v.ull = va_arg (*text->args_ptr, long long unsigned);
+ break;
+ default: abort ();
+
+ }
+ break;
+
+ case 'p':
+ text->arg_array[i].v.ptr = va_arg (*text->args_ptr, void *);
+ break;
+
+ case LOCATION_D_TYPE:
+ text->arg_array[i].v.ptr = va_arg (*text->args_ptr, tree);
+ break;
+
+ case LOCATION_T_TYPE:
+ text->arg_array[i].v.ptr = va_arg (*text->args_ptr, location_t *);
+ break;
+
+ default:
+ pp_helper_abort ("Unknown output specifier during value copy.", text);
+ }
+
+ }
+
+ /* We have established the type/value of arguments when we return. */
+
+ return;
+ }
+
/* Format a message pointed to by TEXT. The following format specifiers are
recognized as being client independent:
%d, %i: (signed) integer in base ten.
*************** pp_base_indent (pretty_printer *pp)
*** 176,194 ****
%c: character.
%s: string.
%p: pointer.
! %m: strerror(text->err_no) - does not consume a value from args_ptr.
%%: `%'.
%*.s: a substring the length of which is specified by an integer.
! %H: location_t. */
! void
pp_base_format_text (pretty_printer *pp, text_info *text)
{
for (; *text->format_spec; ++text->format_spec)
{
int precision = 0;
bool wide = false;
! /* Ignore text. */
{
const char *p = text->format_spec;
while (*p && *p != '%')
--- 794,823 ----
%c: character.
%s: string.
%p: pointer.
! %m: strerror (text->err_no) - does not consume a value from args_ptr.
%%: `%'.
%*.s: a substring the length of which is specified by an integer.
! %H: location_t.
!
! Addition: positional parameter.
! %[0-9]${d,i,u,o,x,...,H} */
!
! void
pp_base_format_text (pretty_printer *pp, text_info *text)
{
+ int arg_index = -1; /* for positional format specifier. */
+ int has_processed_one = 0; /* has processed specifiers. (counter) */
+ int use_pos_specifier = 0; /* %d$c form positional specifier was found. */
+
+ text->original_format_spec = text->format_spec; /* save the original. */
+
for (; *text->format_spec; ++text->format_spec)
{
int precision = 0;
bool wide = false;
! /* Misleading old comment "Ignore text." */
! /* Rather We output text as is (!) */
{
const char *p = text->format_spec;
while (*p && *p != '%')
*************** pp_base_format_text (pretty_printer *pp,
*** 197,206 ****
text->format_spec = p;
}
if (*text->format_spec == '\0')
break;
! /* We got a '%'. Parse precision modifiers, if any. */
switch (*++text->format_spec)
{
case 'w':
--- 826,883 ----
text->format_spec = p;
}
+ /* assert: text->format_spec == '\0'
+ || text->format_spec == '%' */
+
if (*text->format_spec == '\0')
break;
! /* We got a '%'. Parse precision modifiers, if any.
! We also need to handle [0-9] as in %1$d */
!
! if (isdigit (text->format_spec[1]))
! {
! if (text->format_spec[2] == '$')
! {
! char tmp[2];
!
! tmp[1] = '\0';
! tmp[0] = (text->format_spec)[1];
! arg_index = atoi (tmp);
!
! if (arg_index == 0)
! pp_helper_abort ("The digit that comes after % must be non-zero.\n", text);
!
! if (!use_pos_specifier)
! {
! if (has_processed_one > 1)
! pp_helper_abort ("We can't mix %d and %n$d form\n", text);
! pp_build_argument_array (text->original_format_spec, pp, text);
! }
! use_pos_specifier = 1;
!
! /* after the above call to pp_build_argument_array (),
! we know the value (and type) for each argument. */
!
! text->format_spec += 2;
!
! }
! else
! {
! /* we have seen % and digit as in '%1',
! but it is not followed by '$' */
!
! if (isdigit ((text->format_spec)[2]))
! pp_helper_abort ("we handle only 1-9 in %d$ style positional parameter.\n", text);
! else
! pp_helper_abort ("we have seen a percent sign followed by a digit, but it is not followed by '$'\n", text);
! }
! }
!
! /* assert:
! text->format_spec points at % as in % [non-digit]
! || text->format_spec points at $ as in % [digit] $ */
!
switch (*++text->format_spec)
{
case 'w':
*************** pp_base_format_text (pretty_printer *pp,
*** 219,325 ****
}
/* We don't support precision beyond that of "long long". */
if (precision > 2)
! abort();
switch (*text->format_spec)
{
case 'c':
! pp_character (pp, va_arg (*text->args_ptr, int));
break;
case 'd':
case 'i':
if (wide)
! pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT));
else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, int, "d");
break;
case 'o':
! if (wide)
! pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "u");
break;
case 's':
! pp_string (pp, va_arg (*text->args_ptr, const char *));
break;
case 'p':
! pp_pointer (pp, va_arg (*text->args_ptr, void *));
break;
case 'u':
if (wide)
! pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "u");
break;
case 'x':
if (wide)
! pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "x");
break;
case 'm':
pp_string (pp, xstrerror (text->err_no));
break;
case '%':
pp_character (pp, '%');
break;
case 'H':
{
! const location_t *locus = va_arg (*text->args_ptr, location_t *);
! pp_string (pp, "file '");
! pp_string (pp, locus->file);
! pp_string (pp, "', line ");
! pp_decimal_int (pp, locus->line);
}
break;
case '.':
! {
! int n;
! const char *s;
! /* We handle no precision specifier but `%.*s'. */
! if (*++text->format_spec != '*')
! abort ();
! else if (*++text->format_spec != 's')
! abort ();
! n = va_arg (*text->args_ptr, int);
! s = va_arg (*text->args_ptr, const char *);
! pp_append_text (pp, s, s + n);
! }
break;
default:
! if (!pp_format_decoder (pp) || !(*pp_format_decoder (pp)) (pp, text))
{
/* Hmmm. The client failed to install a format translator
but called us with an unrecognized format. Or, maybe, the
translated string just contains an invalid format, or
has formats in the wrong order. Sorry. */
! abort ();
}
}
}
}
/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
settings needed by BUFFER for a verbatim formatting. */
! void
pp_base_format_verbatim (pretty_printer *pp, text_info *text)
{
diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
--- 896,1170 ----
}
/* We don't support precision beyond that of "long long". */
if (precision > 2)
! pp_helper_abort ("Too many precision 'l' specfied.", text);
!
! if (use_pos_specifier
! && (arg_index <= 0 || arg_index > 9))
! pp_helper_abort ("Argument index out of range.\n", text);
!
switch (*text->format_spec)
{
case 'c':
! if (!use_pos_specifier)
! pp_character (pp, va_arg (*text->args_ptr, int)) ;
! else
! pp_character (pp, text->arg_array[arg_index].v.i);
break;
case 'd':
case 'i':
if (wide)
! {
! if (!use_pos_specifier)
! pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT));
! else
! pp_wide_integer (pp, text->arg_array[arg_index].v.hwi);
! }
else
! {
! if (use_pos_specifier)
! pp_integer_with_precision_NEW (pp, arg_index, text);
! else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, int, "d");
! }
break;
case 'o':
! if (!use_pos_specifier)
! {
! if (wide)
! pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! else
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "u");
! }
! else
! {
! if (wide)
! pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
! text->arg_array[arg_index].v.uhwi);
! else
! pp_integer_with_precision_NEW
! (pp, arg_index, text);
!
! }
break;
case 's':
! if (!use_pos_specifier)
! pp_string (pp, va_arg (*text->args_ptr, const char *));
! else
! pp_string (pp, text->arg_array[arg_index].v.cptr);
break;
case 'p':
! if (!use_pos_specifier)
! pp_pointer (pp, va_arg (*text->args_ptr, void *));
! else
! pp_pointer (pp, text->arg_array[arg_index].v.ptr);
break;
case 'u':
if (wide)
! {
! if (!use_pos_specifier)
! pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! else
! pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
! text->arg_array[arg_index].v.uhwi);
! }
else
! {
! if (!use_pos_specifier)
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "u");
! else
! pp_integer_with_precision_NEW
! (pp, arg_index, text);
! }
break;
case 'x':
if (wide)
! {
! if (!use_pos_specifier)
! pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
! va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! else
! pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
! text->arg_array[arg_index].v.uhwi);
! }
else
! {
! if (!use_pos_specifier)
! pp_integer_with_precision
! (pp, *text->args_ptr, precision, unsigned, "x");
! else
! pp_integer_with_precision_NEW
! (pp, arg_index, text);
! }
break;
case 'm':
pp_string (pp, xstrerror (text->err_no));
+ has_processed_one --; /* Adjust. we don't want to count this. */
break;
case '%':
pp_character (pp, '%');
+ has_processed_one --; /* Adjust. we don't want to count this. */
break;
+ /* In the following, the reference to %H should be taken to
+ include the reference to "%J" as well. */
+ case 'J':
case 'H':
{
! const location_t *locus;
! static location_t l_locus;
!
! if (*text->format_spec == 'H')
! {
! if (!use_pos_specifier)
! locus = va_arg (*text->args_ptr, location_t *);
! else
! locus = (location_t *) text->arg_array[arg_index].v.ptr;
! }
! else if (*text->format_spec == 'J')
! {
! tree np;
! if (!use_pos_specifier)
! {
! np = va_arg (*text->args_ptr, tree);
! l_locus = diagnostic_J_tree2locus (np);
! locus = &l_locus;
! }
! else
! {
! np = (tree) text->arg_array[arg_index].v.ptr;
! l_locus = diagnostic_J_tree2locus (np);
! locus = &l_locus;
! }
! }
! else
! abort ();
! /* We dont format %H if it is the first specifier.
! This is necessary to work with text_specifies_location ()
! in diagnostic.c */
! if (has_processed_one <= 0)
! ;
! else
! {
! pp_string (pp, "file '");
! pp_string (pp, locus->file);
! pp_string (pp, "', line ");
! pp_decimal_int (pp, locus->line);
! }
}
break;
case '.':
!
! if (!use_pos_specifier)
! {
! int n;
! const char *s;
! /* We handle no precision specifier except for string type
! as in `%.*s'.
! E.g., warning ("String = %.*s, extra=%d\n", 10, str, i); */
!
! if (*++text->format_spec != '*')
! pp_helper_abort ("We expected '*' after '.'", text);
! else if (*++text->format_spec != 's')
! pp_helper_abort ("We expected 's' after '*'", text);
! n = va_arg (*text->args_ptr, int);
! if (n <= 0) /* we may want to check this. */
! {
! fprintf (stderr, "diagnostic: string width %d given is not positive.\n", n);
! n = 0;
! }
! s = va_arg (*text->args_ptr, const char *);
! pp_append_text (pp, s, s + n);
! }
! else
! {
! /* we handle %d$.*m$s : we have seen "period". */
!
! int a;
! char tmp[2];
! int c;
! int n;
! char *s;
!
! if (*++text->format_spec != '*')
! pp_helper_abort ("We expected '*' afer '.'", text);
!
! c = *++text->format_spec;
! if (!isdigit (c))
! pp_helper_abort ("We expected a digit after '*'", text);
! tmp[0] = c; tmp[1] = '\0';
! a = atoi (tmp);
! c = *++text->format_spec;
! if (c != '$')
! pp_helper_abort ("We expected a '$' after a digit", text);
! c = *++text->format_spec;
! if (c != 's')
! pp_helper_abort ("We expected an 's' after '$'", text);
! n = text->arg_array[a].v.i;
! if (n <= 0)
! {
! fprintf (stderr, "diagnostic: string width %d at %d is not positive.\n", n, a);
! n = 0;
! }
! s = text->arg_array[arg_index].v.cptr;
! pp_append_text (pp, s, s + n);
!
! }
break;
default:
!
! text->index_num = arg_index;
!
! /* We decided to use text->format_spec even
! in the case of PRINT_ARG_VALUE case (positional
! parameter support), but still set this just in case. */
! text->format_after_percent_or_dollar = text->format_spec;
! text->bump_format = 0;
!
! if (use_pos_specifier
! && (arg_index <= 0 || arg_index > 9))
! pp_helper_abort ("arg_index out of range.", text);
!
! if (!pp_format_decoder (pp)
! || !(*pp_format_decoder (pp)) (pp, text,
! use_pos_specifier ?
! PRINT_ARG_VALUE :
! PRINT_ARG_VALUE_AS_BEFORE))
{
/* Hmmm. The client failed to install a format translator
but called us with an unrecognized format. Or, maybe, the
translated string just contains an invalid format, or
has formats in the wrong order. Sorry. */
! pp_helper_abort ("unrecognized format.", text);
}
+
+ /* adjust the pointer by the bytes understood by the
+ custom format decoder. */
+ if (use_pos_specifier && text->bump_format > 1)
+ text->format_spec += (text->bump_format - 1);
}
+ has_processed_one ++;
}
}
/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
settings needed by BUFFER for a verbatim formatting. */
! void
pp_base_format_verbatim (pretty_printer *pp, text_info *text)
{
diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
Index: gcc/pretty-print.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.h,v
retrieving revision 1.10
diff -c -3 -p -r1.10 pretty-print.h
*** gcc/pretty-print.h 25 Aug 2003 19:10:48 -0000 1.10
--- gcc/pretty-print.h 23 Sep 2003 18:11:30 -0000
*************** Software Foundation, 59 Temple Place - S
*** 25,30 ****
--- 25,78 ----
#include "obstack.h"
#include "input.h"
+ /* The type of variable argument arg_array[] (part of
+ text_info) to store type and the value.
+ This is to support positional format specifiers
+ in the form of %1$s, %2$d %3$d, etc.
+
+ Note that we use the arg_array[0].v.cptr to store the format string.
+ The whole array is set to zero before each construction. */
+ typedef struct
+ {
+ int typespec ; /* type 'd', etc. */
+ int precision ; /* to handle %d, %ld, %lld */
+ char format [5]; /* %lld at the longest. */
+ char custom_format[4]; /* CUSTOM decoder format. May contain #+, etc. */
+ union { /* holding the value of argument */
+ int i;
+ unsigned int ui;
+ short s;
+ unsigned short us;
+ char c;
+ unsigned char uc;
+ long l;
+ unsigned long ul;
+ long long ll;
+ unsigned long long ull;
+ HOST_WIDE_INT hwi;
+ unsigned HOST_WIDE_INT uhwi;
+ void *ptr;
+ char *cptr;
+ int *iptr;
+ long *lptr;
+ long long *llptr;
+ location_t l_ptr;
+ } v;
+ } argtype_t;
+
+
+ /* The type of an action to custom defined format decoder:
+ to return information or perform copy/print action
+ for positional parameter processing. */
+ typedef enum
+ {
+ GET_ARG_TYPE = 2,
+ COPY_ARG_VALUE = 3,
+ PRINT_ARG_VALUE = 4,
+ PRINT_ARG_VALUE_AS_BEFORE = 5 /* as before: no positional support */
+ } arg_decode_action;
+
+
/* The type of a text to be formatted according a format specification
along with a list of things. */
typedef struct
*************** typedef struct
*** 32,37 ****
--- 80,98 ----
const char *format_spec;
va_list *args_ptr;
int err_no; /* for %m */
+
+ /* Below is for positional argument support */
+
+ const char *original_format_spec; /* this remains unchanged. */
+ argtype_t arg_array[10 + 1]; /* arg_array[0].v.cptr holds
+ the original format pointer.
+ Argument is counted from postion no. 1. */
+ int arg_max;
+ const char *format_after_percent_or_dollar; /* for GET_ARG_TYPE, COPY_ARG_VALUE */
+ int index_num; /* argument index for custom decoder. */
+ int bump_format ; /* GET_ARG_TYPE: returns
+ how many bytes of format chars will
+ be eaten by custom decoder. */
} text_info;
/* How often diagnostics are prefixed by their locations:
*************** typedef enum
*** 76,82 ****
A client-supplied formatter returns true if everything goes well,
otherwise it returns false. */
typedef struct pretty_print_info pretty_printer;
! typedef bool (*printer_fn) (pretty_printer *, text_info *);
/* Client supplied function used to decode formats. */
#define pp_format_decoder(PP) pp_base (PP)->format_decoder
--- 137,143 ----
A client-supplied formatter returns true if everything goes well,
otherwise it returns false. */
typedef struct pretty_print_info pretty_printer;
! typedef bool (*printer_fn) (pretty_printer *, text_info *, arg_decode_action);
/* Client supplied function used to decode formats. */
#define pp_format_decoder(PP) pp_base (PP)->format_decoder
*************** extern void pp_base_indent (pretty_print
*** 257,261 ****
--- 318,326 ----
extern void pp_base_newline (pretty_printer *);
extern void pp_base_character (pretty_printer *, int);
extern void pp_base_string (pretty_printer *, const char *);
+
+ /* in diagnostic.c */
+ extern location_t diagnostic_J_tree2locus (tree t);
+
#endif /* GCC_PRETTY_PRINT_H */
Index: gcc/toplev.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.829
diff -c -3 -p -r1.829 toplev.c
*** gcc/toplev.c 22 Sep 2003 05:09:12 -0000 1.829
--- gcc/toplev.c 23 Sep 2003 18:11:35 -0000
*************** crash_signal (int signo)
*** 1331,1337 ****
}
/* Arrange to dump core on error. (The regular error message is still
! printed first, except in the case of abort().) */
static void
setup_core_dumping (void)
--- 1331,1337 ----
}
/* Arrange to dump core on error. (The regular error message is still
! printed first, except in the case of abort ().) */
static void
setup_core_dumping (void)
*************** init_asm_output (const char *name)
*** 4011,4035 ****
/* Default tree printer. Handles declarations only. */
static bool
! default_tree_printer (pretty_printer * pp, text_info *text)
{
! switch (*text->format_spec)
{
! case 'D':
! case 'F':
! case 'T':
! {
! tree t = va_arg (*text->args_ptr, tree);
! const char *n = DECL_NAME (t)
! ? (*lang_hooks.decl_printable_name) (t, 2)
! : "<anonymous>";
! pp_string (pp, n);
! }
! return true;
- default:
- return false;
}
}
/* Initialization of the front end environment, before command line
--- 4011,4091 ----
/* Default tree printer. Handles declarations only. */
static bool
! default_tree_printer (pretty_printer * pp, text_info *text, arg_decode_action a)
{
!
! /* We share the code for printing between
! positional and non-positional specifier cases */
!
! if (a == PRINT_ARG_VALUE_AS_BEFORE
! || a == PRINT_ARG_VALUE)
{
! tree t;
! if (a == PRINT_ARG_VALUE)
! t = (tree) text->arg_array[text->index_num].v.ptr ;
! else
! t = va_arg (*text->args_ptr, tree);
!
! switch (*text->format_spec)
! {
! case 'D':
! case 'F':
! case 'T':
! {
! const char *n = DECL_NAME (t)
! ? (*lang_hooks.decl_printable_name) (t, 2)
! : "<anonymous>";
! pp_string (pp, n);
! }
! return true;
!
! default:
! return false;
! }
! }
! else if (a == GET_ARG_TYPE)
! {
! text->bump_format = 0;
!
! switch (*text->format_after_percent_or_dollar)
! {
! case 'D':
! case 'F':
! case 'T':
! {
! text->bump_format = 1;
! text->arg_array[text->index_num].custom_format[0]
! = *text->format_after_percent_or_dollar;
! }
! return true;
! default:
! return false;
! }
! }
! else if (a == COPY_ARG_VALUE)
! {
! text->bump_format = 0;
!
! switch (*text->format_after_percent_or_dollar)
! {
! case 'D':
! case 'F':
! case 'T':
! {
! text->bump_format = 1;
! text->arg_array[text->index_num].v.ptr
! = (void *) va_arg (*text->args_ptr, tree);
! }
! return true;
! default:
! return false;
! }
!
}
+ else
+ abort ();
+
}
/* Initialization of the front end environment, before command line
*************** toplev_main (unsigned int argc, const ch
*** 4507,4512 ****
--- 4563,4719 ----
/* Initialization of GCC's environment, and diagnostics. */
general_init (argv[0]);
+
+ #if 0
+ {
+ /* This is a test code for checking the
+ positional parameter support in diagnostic routines.
+ I wonder where we should keep this code.
+ As I explained in my post to gcc-patches , there is no easy way to
+ test the positional parameter support without
+ using an existing program and inserting this test code
+ somewhere. */
+
+ #include <errno.h>
+ int i;
+ long t;
+ long long ill;
+ long long xll;
+ extern void warning (const char *msgid, ...);
+
+ static char str [] = "123456789A123456789A123456789A";
+
+ i = 1234;
+ t = 0x0FFFFFFl;
+ ill = (long long) t * t;
+ xll = 0x0123456789ABCDEFull;
+
+
+ warning ("Test diagnostic.\n");
+
+ warning ("integer=%d, pointer=%p, char=%c", i, &t, 'c');
+
+ warning ("\nPointer value print\n");
+
+ fprintf (stderr, "pointer=%p\n", (void *) &t);
+ warning ("1st: pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+ warning ("2nd: pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+ warning ("3rd: pointer=%1$p, char=%3$c, integer=%2$d", &t, i, 'c');
+ warning ("pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+
+
+ warning ("\nOne argument");
+ warning ("integer=%1$d", i);
+ warning ("char =%1$c", 'c');
+ warning ("pointer=%1$p", &t);
+ warning ("long=%1$ld", t);
+ warning ("long=%1$lx", t);
+
+
+ /* long */
+ warning ("long=(x) %1$lx", t);
+ fprintf (stderr, " ordinary printf: %lx\n", t);
+ warning ("long=(o) %1$lo", t);
+ fprintf (stderr, " ordinary printf: %lo\n", t);
+ warning ("long=(d) %1$ld", t);
+ fprintf (stderr, " ordinary printf: %ld\n", t);
+
+
+ /* long long */
+
+ warning ("long long=(d) %1$lld", ill);
+ fprintf (stderr, "ordinary fprintf(): %lld\n", ill);
+
+
+ warning ("long long=(x) %1$llx", xll);
+ fprintf (stderr, " ordinary printf: %llx\n", xll);
+
+
+ warning ("long long=(o) %1$llo", xll);
+ fprintf (stderr, " ordinary printf: %llo\n", xll);
+
+
+ warning ("long long=(d) %1$lld", xll);
+ fprintf (stderr, " ordinary printf: %lld\n", xll);
+
+ /* wide ? */
+
+ warning ("Wide\n");
+ warning ("wide=(wd) %1$wd", t);
+ warning ("wide=(wx) %1$wx", t);
+ warning ("wide=(wo) %1$wo", t);
+
+ warning ("\nTwo arguments");
+ warning ("integer=%1$d, char=%2$c", i, 'c');
+ warning ("char =%2$c, integer=%1$d", i, 'c');
+
+ warning ("\nThree Arguments\n");
+ warning ("char=%3$c, integer=%1$d, pointer=%2$p", i, &t, 'c');
+
+ warning ("char=%c, integer=%d, pointer=%p", 'c', i, &t);
+ warning ("pointer=%3$p, char=%1$c, integer=%2$d", 'c', i, &t);
+ warning ("char=%1$c, integer=%2$d, pointer=%3$p", 'c', i, &t);
+
+ warning ("integer=%d, long=%ld, long long=%lld", i, t, ill);
+ warning ("long=%2$ld, long long=%3$lld, int=%1$d", i, t, ill);
+ warning ("long long=%3$lld, int=%1$d, long=%2$ld", i, t, ill);
+
+ warning ("pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+
+ warning ("long long=%lld, long=%ld, int=%d", ill, t, i);
+ warning ("long=%2$ld, int=%3$d, long long=%1$lld", ill, t, i);
+ warning ("int=%3$d, long long=%1$lld, long=%2$ld", ill, t, i);
+
+
+ /* String and its width*/
+ warning ("\nString");
+
+ warning ("String =%s", str);
+ warning ("String =%1$s", str);
+ fprintf (stderr, "ordinary fprintf(): %s\n", str);
+
+ warning ("String = %.*s, extra=%d", 10, str, i);
+ warning ("String = %3$.*1$s, extra=%2$d", 10, i, str);
+ warning ("String = %2$.*1$s, extra=%3$d", 10, str, i);
+ fprintf (stderr, "ordinary fprintf(): %.*s\n", 10, str);
+
+ /* modified test from a post by Jonathan Lennox */
+ {
+ const char *str = "Hello!";
+ warning ("String = %2$.*1$s, extra=%3$d", 10, str, i);
+ warning ("\n%.*s\n%.*s\n%.*s\n%.*s\n%.*s\n%.*s",
+ 1, str, 2, str, 3, str, 4, str, 5, str, 6, str);
+ warning ("\n%1$.*2$s\n%1$.*3$s\n%1$.*4$s\n%1$.*5$s\n%1$.*6$s\n%1$.*7$s",
+ str, 1, 2, 3, 4, 5, 6);
+ }
+
+
+ /* %% and %m */
+
+ warning ("This is one %% (percent sign) and error code message: could be random <<%m>>");
+
+
+ errno = EPIPE;
+ warning ("int=%1$d, long long=%2$lld, %% (percent sign) and error message should be for EPIPE <<%m>>", i, ill);
+
+
+ /* should abort: we can't mix two forms. */
+ warning ("Should abort: integer=%d, pointer=%p, char=%3$c\n", i, &t, 'c');
+
+ /* should abort because %3$whatever is missing. */
+ warning ("Should abort: char=%4$p, integer=%1$d, pointer=%2$p\n", i, &t, 'c');
+
+ /* should abort: we can't mix two forms */
+ warning ("Should abort: integer=%1$d, pointer=%2$p, char=%c\n", i, &t, 'c');
+
+ /* should abort: 0 after %. */
+ warning ("Should abort: integer=%0$d, pointer=%2$p, char=%3c\n", i, &t, 'c');
+
+ }
+
+ #endif
+
+
/* Parse the options and do minimal processing; basically just
enough to default flags appropriately. */
Index: gcc/cp/error.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.238
diff -c -3 -p -r1.238 error.c
*** gcc/cp/error.c 22 Sep 2003 05:09:23 -0000 1.238
--- gcc/cp/error.c 23 Sep 2003 18:11:40 -0000
*************** static void print_instantiation_partial_
*** 96,103 ****
static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
static void cp_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
!
! static bool cp_printer (pretty_printer *, text_info *);
static void pp_non_consecutive_character (cxx_pretty_printer *, int);
static tree locate_error (const char *, va_list);
static location_t location_of (tree);
--- 96,102 ----
static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
static void cp_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
! static bool cp_printer (pretty_printer *, text_info *, arg_decode_action);
static void pp_non_consecutive_character (cxx_pretty_printer *, int);
static tree locate_error (const char *, va_list);
static location_t location_of (tree);
*************** dump_expr (tree t, int flags)
*** 1550,1556 ****
}
else
{
! if (TREE_OPERAND (t,0) != NULL_TREE
&& TREE_TYPE (TREE_OPERAND (t, 0))
&& NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
dump_expr (TREE_OPERAND (t, 0), flags);
--- 1549,1555 ----
}
else
{
! if (TREE_OPERAND (t, 0) != NULL_TREE
&& TREE_TYPE (TREE_OPERAND (t, 0))
&& NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
dump_expr (TREE_OPERAND (t, 0), flags);
*************** print_instantiation_context (void)
*** 2268,2276 ****
%P function parameter whose position is indicated by an integer.
%Q assignment operator.
%T type.
! %V cv-qualifier. */
static bool
! cp_printer (pretty_printer *pp, text_info *text)
{
int verbose = 0;
const char *result;
--- 2267,2277 ----
%P function parameter whose position is indicated by an integer.
%Q assignment operator.
%T type.
! %V cv-qualifier.
!
! Modified to support postional format parameter. */
static bool
! cp_printer (pretty_printer *pp, text_info *text, arg_decode_action a)
{
int verbose = 0;
const char *result;
*************** cp_printer (pretty_printer *pp, text_inf
*** 2279,2316 ****
#define next_lang va_arg (*text->args_ptr, enum languages)
#define next_int va_arg (*text->args_ptr, int)
! if (*text->format_spec == '+')
! ++text->format_spec;
! if (*text->format_spec == '#')
! {
! verbose = 1;
! ++text->format_spec;
! }
!
! switch (*text->format_spec)
! {
! case 'A': result = args_to_string (next_tree, verbose); break;
! case 'C': result = code_to_string (next_tcode); break;
! case 'D': result = decl_to_string (next_tree, verbose); break;
! case 'E': result = expr_to_string (next_tree); break;
! case 'F': result = fndecl_to_string (next_tree, verbose); break;
! case 'L': result = language_to_string (next_lang); break;
! case 'O': result = op_to_string (next_tcode); break;
! case 'P': result = parm_to_string (next_int); break;
! case 'Q': result = assop_to_string (next_tcode); break;
! case 'T': result = type_to_string (next_tree, verbose); break;
! case 'V': result = cv_to_string (next_tree, verbose); break;
! default:
! return false;
}
- pp_base_string (pp, result);
- return true;
#undef next_tree
#undef next_tcode
#undef next_lang
#undef next_int
}
static void
--- 2280,2423 ----
#define next_lang va_arg (*text->args_ptr, enum languages)
#define next_int va_arg (*text->args_ptr, int)
! #define pos_next_tree ((tree) text->arg_array[i].v.ptr)
! #define pos_next_tcode ((enum tree_code) text->arg_array[i].v.i)
! #define pos_next_lang ((enum languages) text->arg_array[i].v.i)
! #define pos_next_int (text->arg_array[i].v.i)
!
!
! #define x_next_tree ((a == PRINT_ARG_VALUE) ? pos_next_tree : next_tree)
! #define x_next_tcode ((a == PRINT_ARG_VALUE) ? pos_next_tcode : next_tcode)
! #define x_next_lang ((a == PRINT_ARG_VALUE) ? pos_next_lang : next_lang)
! #define x_next_int ((a == PRINT_ARG_VALUE) ? pos_next_int : next_int)
!
!
! /* We share the code for printing between
! positional and non-positional specifier cases */
!
! if (a == PRINT_ARG_VALUE_AS_BEFORE
! || a == PRINT_ARG_VALUE)
! {
! int i = text->index_num;
!
! text->bump_format = 0;
!
! if (*text->format_spec == '+')
! ++text->format_spec;
! if (*text->format_spec == '#')
! {
! verbose = 1;
! ++text->format_spec;
! }
!
! switch (*text->format_spec)
! {
! case 'A': result = args_to_string (x_next_tree, verbose); break;
! case 'C': result = code_to_string (x_next_tcode); break;
! case 'D': result = decl_to_string (x_next_tree, verbose); break;
! case 'E': result = expr_to_string (x_next_tree); break;
! case 'F': result = fndecl_to_string (x_next_tree, verbose); break;
! case 'L': result = language_to_string (x_next_lang); break;
! case 'O': result = op_to_string (x_next_tcode); break;
! case 'P': result = parm_to_string (x_next_int); break;
! case 'Q': result = assop_to_string (x_next_tcode); break;
! case 'T': result = type_to_string (x_next_tree, verbose); break;
! case 'V': result = cv_to_string (x_next_tree, verbose); break;
! default:
! return false;
! }
!
! pp_base_string (pp, result);
! return true;
}
+ else if (a == GET_ARG_TYPE)
+ {
+ text->bump_format = 0;
+ if (*text->format_after_percent_or_dollar == '+')
+ text->arg_array[text->index_num].custom_format[text->bump_format++] =
+ *text->format_after_percent_or_dollar++;
+ if (*text->format_spec == '#')
+ {
+ verbose = 1;
+ text->arg_array[text->index_num].custom_format[text->bump_format++] =
+ *text->format_after_percent_or_dollar++;
+ }
+
+ switch (*text->format_after_percent_or_dollar)
+ {
+ case 'A':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'L':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'T':
+ case 'V':
+ text->arg_array[text->index_num].custom_format[text->bump_format++] =
+ *text->format_after_percent_or_dollar;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+ else if (a == COPY_ARG_VALUE)
+ {
+ int i = text->index_num;
+
+ text->bump_format = 0;
+
+ if (*text->format_after_percent_or_dollar == '+')
+ ++text->format_after_percent_or_dollar, ++text->bump_format;
+ if (*text->format_spec == '#')
+ {
+ verbose = 1;
+ ++text->format_after_percent_or_dollar;
+ ++text->bump_format;
+ }
+
+ switch (*text->format_after_percent_or_dollar)
+ {
+ case 'A': text->arg_array[i].v.ptr = (void *) next_tree ; break;
+ case 'C': text->arg_array[i].v.ptr = (void *) next_tcode; break;
+ case 'D': text->arg_array[i].v.ptr = (void *) next_tree; break;
+ case 'E': text->arg_array[i].v.ptr = (void *) next_tree; break;
+ case 'F': text->arg_array[i].v.ptr = (void *) next_tree; break;
+ case 'L': text->arg_array[i].v.i = next_lang; break;
+ case 'O': text->arg_array[i].v.i = next_tcode; break;
+ case 'P': text->arg_array[i].v.i = next_int; break;
+ case 'Q': text->arg_array[i].v.i = next_tcode; break;
+ case 'T': text->arg_array[i].v.ptr = next_tree; break;
+ case 'V': text->arg_array[i].v.ptr = next_tree; break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+ else
+ abort ();
#undef next_tree
#undef next_tcode
#undef next_lang
#undef next_int
+
+ #undef pos_next_tree
+ #undef pos_next_tcode
+ #undef pos_next_lang
+ #undef pos_next_int
+
+ #undef x_next_tree
+ #undef x_next_tcode
+ #undef x_next_lang
+ #undef x_next_int
+
}
static void
*************** pp_non_consecutive_character (cxx_pretty
*** 2324,2330 ****
}
/* These are temporary wrapper functions which handle the historic
! behavior of cp_*_at. */
static tree
locate_error (const char *msgid, va_list ap)
--- 2431,2441 ----
}
/* These are temporary wrapper functions which handle the historic
! behavior of cp_*_at.
!
! We don't have to worry about positional format specifier
! in this function since this receives msgid, i.e., the original format string
! before translation that should NOT contain such postional specifier. */
static tree
locate_error (const char *msgid, va_list ap)
While we are at it,
someone might want to answer the question below.
Now, another question:
While creating the patch, I noticed that a call to pp_string () in
cp_printer() in cp/error.c is now modified to pp_base_string ().
I suppose this is intentional.
However, if so, should we not modify the call to pp_string() in
- default_printer () in toplev.c,
- c_tree_printer () in c-objc-common.c
to pp_base_string() as well?