This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Support %N$/*N$ style format arguments in GCC diagnostics


On Wed, May 18, 2005 at 05:34:52PM +0000, Joseph S. Myers wrote:
> > BTW, shouldn't we implement %n$ style arguments in addition to % ones?
> > It seems e.g. several turkish translations relied on this...
> 
> Chiaki Ishikawa had a long patch series attempting to implement them but I 
> don't think they ever got in reviewable form or were following an approach 
> Zack liked.

Seeing that the last po commit added a big number of %N$ arguments, I wrote
following patch.

I tried to make the requirements match POSIX *printf requirements.
pp_base_format_text works in 3 phases, first it scans the format string
and records the arguments, then, with optional help of a hook stores
the arguments into a union and finally prints them as it used to print them
before, only instead of va_arg directly it uses that union.

I'm not sure what to do about the special case for %H/%J at the beginning
of (some of) the format strings.  The patch below doesn't take them into
account at all, so those must be really %H resp. %J with no
modifiers/position specification etc., and as their argument is eaten by the
time we reach pp_base_format_text, %J%2$d%1$d, this is the hidden tree argument
and then 2 integers after it.  Not sure if this would not confuse
translators.  So alternatively we could perhaps cooperate with
pp_base_prepare_to_format, if using positional arguments the initial
%H would need to be %1$H (resp. %1$J for %J) and other arguments would
count from 2.  What do you think?

Tested with make check and printing a couple of weirdo warning calls
I wrote just to test it out.

2005-05-20  Jakub Jelinek  <jakub@redhat.com>

	* pretty-print.h (pp_fmt_arg): New type.
	(PP_NL_ARGMAX): Define.
	(arg_fetch_fn): New function type.
	(printer_fn): Add pp_fmt_arg * argument.
	(struct pretty_print_info): Add format_arg_fetch field.
	* pretty-print.c (pp_base_format_text): Add support for numbered
	arguments (%N$ resp. *N$ notation) and %.Ns.
	(pp_integer_with_precision): Adjust.
	* diagnostic.h (diagnostic_format_arg_fetch): Define.
	* toplev.c (default_tree_arg_fetch): New function.
	(default_tree_printer): Add ARG argument.  Fetch value from
	ARG->data union rather than from va_arg.
	(general_init): Initialize pp_format_arg_fetch.
	* c-objc-common.c (c_tree_arg_fetch): New function.
	(c_tree_printer): Add ARG argument.  Fetch value from
	ARG->data union rather than from va_arg.
	(c_objc_common_init): Initialize diagnostic_format_arg_fetch.

	* error.c (cp_arg_fetch): New function.
	(cp_printer): Add ARG argument.  Fetch value from ARG->data
	union rather than from va_arg.
	(init_error): Initialize diagnostic_format_arg_fetch.

--- gcc/pretty-print.h.jj	2004-11-11 10:37:33.000000000 +0100
+++ gcc/pretty-print.h	2005-05-20 18:05:54.000000000 +0200
@@ -1,5 +1,5 @@
 /* Various declarations for language-independent pretty-print subroutines.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
 
 This file is part of GCC.
@@ -72,13 +72,40 @@ typedef enum
   pp_none, pp_before, pp_after
 } pp_padding;
 
+typedef struct
+{
+  unsigned char code;
+  union
+  {
+    int pp_d_int;
+    unsigned pp_d_uint;
+    long int pp_d_long;
+    unsigned long int pp_d_ulong;
+    long long int pp_d_longlong;
+    unsigned long long int pp_d_ulonglong;
+    HOST_WIDE_INT pp_d_hwi;
+    unsigned HOST_WIDE_INT pp_d_uhwi;
+    const char *pp_d_string;
+    void *pp_d_ptr;
+    location_t *pp_d_locus;
+    tree pp_d_tree;
+  } data;
+} pp_fmt_arg;
+
+/* Maximum number of format string arguments.  */
+#define PP_NL_ARGMAX	30
+
 /* The type of a hook that formats client-specific data onto a pretty_pinter.
    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 *);
+typedef bool (*arg_fetch_fn) (pretty_printer *, text_info *, pp_fmt_arg *);
+typedef bool (*printer_fn) (pretty_printer *, text_info *, pp_fmt_arg *);
+
+/* Client supplied function used to fetch format arguments.  */
+#define pp_format_arg_fetch(PP) pp_base (PP)->format_arg_fetch
 
-/* Client supplied function used to decode formats.  */
+/* Client supplied function used to decode and print formats.  */
 #define pp_format_decoder(PP) pp_base (PP)->format_decoder
 
 /* TRUE if a newline character needs to be added before further
@@ -126,10 +153,16 @@ struct pretty_print_info
   /* Current prefixing rule.  */
   diagnostic_prefixing_rule_t prefixing_rule;
 
+  /* If non-NULL, this function should fetch argument for format argument
+     in ARG->code from *TEXT->args_pts using VA_ARG and store it into
+     ARG->data union.  */
+  arg_fetch_fn format_arg_fetch;
+
   /* If non-NULL, this function formats a TEXT into the BUFFER.  When called,
      TEXT->format_spec points to a format code.  FORMAT_DECODER should call
      pp_string (and related functions) to add data to the BUFFER.
-     FORMAT_DECODER can read arguments from *TEXT->args_pts using VA_ARG.
+     FORMAT_DECODER can use argument previously fetched by FORMAT_ARG_FETCH
+     into ARG->data union.
      If the BUFFER needs additional characters from the format string, it
      should advance the TEXT->format_spec as it goes.  When FORMAT_DECODER
      returns, TEXT->format_spec should point to the last character processed.
--- gcc/pretty-print.c.jj	2005-04-29 09:18:04.000000000 +0200
+++ gcc/pretty-print.c	2005-05-20 21:17:38.000000000 +0200
@@ -35,28 +35,28 @@ Software Foundation, 59 Temple Place - S
 #define pp_formatted_text_data(PP) \
    ((const char *) obstack_base (&pp_base (PP)->buffer->obstack))
 
-/* Format an integer given by va_arg (ARG, type-specifier T) where
+/* Format an integer given by ARG[I].data.T where
    type-specifier is a precision modifier as indicated by PREC.  F is
    a string used to construct the appropriate format-specifier.  */
-#define pp_integer_with_precision(PP, ARG, PREC, T, F)       \
-  do                                                         \
-    switch (PREC)                                            \
-      {                                                      \
-      case 0:                                                \
-        pp_scalar (PP, "%" F, va_arg (ARG, T));              \
-        break;                                               \
-                                                             \
-      case 1:                                                \
-        pp_scalar (PP, "%l" F, va_arg (ARG, long T));        \
-        break;                                               \
-                                                             \
-      case 2:                                                \
-        pp_scalar (PP, "%ll" F, va_arg (ARG, long long T));  \
-        break;                                               \
-                                                             \
-      default:                                               \
-        break;                                               \
-      }                                                      \
+#define pp_integer_with_precision(PP, ARG, I, PREC, T, F)       \
+  do								\
+    switch (PREC)						\
+      {								\
+      case 0:							\
+	pp_scalar (PP, "%" F, ARG[I].data.T##int);		\
+	break;							\
+								\
+      case 1:							\
+	pp_scalar (PP, "%l" F, ARG[I].data.T##long);		\
+	break;							\
+								\
+      case 2:							\
+	pp_scalar (PP, "%ll" F, ARG[I].data.T##longlong);	\
+	break;							\
+								\
+      default:							\
+	break;							\
+      }								\
   while (0)
 
 
@@ -218,33 +218,228 @@ pp_base_prepare_to_format (pretty_printe
    %>: closing quote.
    %': apostrophe (should only be used in untranslated messages;
        translations should use appropriate punctuation directly).
-   %.*s: a substring the length of which is specified by an integer.
+   %.*s: a substring the length of which is specified by an argument
+	 integer.
+   %Ns: likewise, but length specified as constant in the format string.
    %H: location_t.
-   Flag 'q': quote formatted text (must come immediately after '%').  */
+   Flag 'q': quote formatted text (must come immediately after '%').
+   Arguments can be used sequentially, or through %N$ resp. *N$ notation
+   Nth argument after the format string (and optional argument matching
+   initial %H resp. %J in the format string handled in
+   pp_base_prepare_to_format).  If %N$/*N$ notation is used, it must
+   be used for all arguments, except %m, %%, %<, %> and %' where either
+   form can be used.  The format string must have conversion specifiers
+   with argument numbers 1 up to highest argument.  A format string
+   can have at most 30 arguments.  */
 void
 pp_base_format_text (pretty_printer *pp, text_info *text)
 {
-  for (; *text->format_spec; ++text->format_spec)
+  pp_fmt_arg args[PP_NL_ARGMAX];
+  const char *p = text->format_spec;
+  unsigned int curarg = 0;
+  bool any_numbered = false, any_unnumbered = false;
+  unsigned int argno;
+
+  /* First phase.  Scan the format string to see if % or %N$ style
+     specifiers are used, record them in the ARGS array.  */
+  memset (args, 0, sizeof (args));
+  for (p = text->format_spec; *p; )
+    if (*p++ == '%')
+      {
+	unsigned int n;
+	unsigned char code;
+	int precision = 0;
+	bool numbered = false;
+
+	if (*p >= '0' && *p <= '9')
+	  {
+	    char *end;
+	    n = strtoul (p, &end, 10) - 1;
+	    gcc_assert (*end == '$');
+	    p = (const char *) (end + 1);
+	    numbered = true;
+	  }
+	else
+	  n = curarg;
+
+	if (*p == 'q')
+	  ++p;
+	switch (*p)
+	  {
+	  case 'w':
+	    precision = 3;
+	    ++p;
+	    break;
+
+	  case 'l':
+	    do
+	      ++precision;
+	    while (*++p == 'l');
+	    /* We don't support precision beyond that of "long long".  */
+	    gcc_assert (precision <= 2);
+	    break;
+
+	  default:
+	    break;
+	  }
+
+	/* %%, %m, %<, %>, %' don't use arguments, so can be used with
+	   both These specifiers don't need any arguments.  */
+	if (strchr ("%m<>'", *p) == NULL)
+	  {
+	    if (numbered)
+	      {
+		any_numbered = true;
+		gcc_assert (! any_unnumbered);
+	      }
+	    else
+	      {
+		any_unnumbered = true;
+		gcc_assert (! any_numbered);
+		++curarg;
+	      }
+	  }
+	else if (!numbered)
+	  {
+	    ++p;
+	    continue;
+	  }
+
+	gcc_assert (n < PP_NL_ARGMAX);
+	if (*p == '+')
+	  ++p;
+	if (*p == '#')
+	  ++p;
+	switch (*p)
+	  {
+	  case '%':
+	  case 'm':
+	  case '<':
+	  case '>':
+	  case '\'':
+	    code = '%';
+	    break;
+	  /* These take {,long,long long,HOST_WIDE_INT} int.  */
+	  case 'd':
+	  case 'i':
+	    code = '0' + precision;
+	    break;
+	  /* These take unsigned {,long,long long,HOST_WIDE_INT} int.  */
+	  case 'o':
+	  case 'u':
+	  case 'x':
+	    code = '5' + precision;
+	    break;
+	  /* We handle '%.Ns' and '%.*s' or '%M$.*N$s' (where M and N are
+	     small unsigned decimal numbers).  */
+	  case '.':
+	    if (p[1] >= '0' && p[1] <= '9')
+	      for (p += 2; *p >= '0' && *p <= '9'; ++p);
+	    else
+	      {
+		unsigned int pn;
+
+		gcc_assert (p[1] == '*');
+		p += 2;
+		if (numbered)
+		  {
+		    char *end;
+
+		    pn = strtoul (p, &end, 10) - 1;
+		    gcc_assert (p != end && *end == '$');
+		    p = (const char *) (end + 1);
+		  }
+		else
+		  {
+		    pn = n;
+		    n = curarg++;
+		    gcc_assert (n < PP_NL_ARGMAX);
+		  }
+
+		gcc_assert (args[pn].code == '\0' || args[pn].code == '0');
+		args[pn].code = '0';
+	      }
+	    gcc_assert (*p == 's');
+	    code = 's';
+	    break;
+	  default:
+	    code = *p;
+	    break;
+	  }
+
+	gcc_assert (args[n].code == '\0' || args[n].code == code);
+	args[n].code = code;
+	++p;
+      }
+
+  /* Second phase.  Fetch the arguments from *text->args_ptr va_list.  */
+  for (argno = 0; argno < PP_NL_ARGMAX; ++argno)
+    {
+      if (args[argno].code == '\0')
+	continue;
+      gcc_assert (argno == 0 || args[argno - 1].code != '\0');
+      switch (args[argno].code)
+	{
+	case '%':
+	  break;
+#define pp_arg_fetch(code, field, type) \
+	case code: \
+	  args[argno].data.pp_d_##field = va_arg (*text->args_ptr, type); \
+	  break
+	pp_arg_fetch ('0', int, int);
+	pp_arg_fetch ('1', long, long int);
+	pp_arg_fetch ('2', longlong, long long int);
+	pp_arg_fetch ('3', hwi, HOST_WIDE_INT);
+	pp_arg_fetch ('5', uint, unsigned int);
+	pp_arg_fetch ('6', ulong, unsigned long int);
+	pp_arg_fetch ('7', ulonglong, unsigned long long int);
+	pp_arg_fetch ('8', uhwi, unsigned HOST_WIDE_INT);
+	pp_arg_fetch ('c', int, int);
+	pp_arg_fetch ('p', ptr, void *);
+	pp_arg_fetch ('s', string, const char *);
+	pp_arg_fetch ('H', locus, location_t *);
+#undef pp_arg_fetch
+	default:
+	  {
+	    bool ok;
+
+	    gcc_assert (pp_format_arg_fetch (pp));
+	    ok = pp_format_arg_fetch (pp) (pp, text, &args[argno]);
+	    gcc_assert (ok);
+	    break;
+	  }
+	}
+    }
+
+  /* Third phase.  Actually print it.  */
+  for (curarg = 0; *text->format_spec; ++text->format_spec, ++curarg)
     {
       int precision = 0;
       bool wide = false;
       bool quoted = false;
 
       /* Ignore text.  */
-      {
-	const char *p = text->format_spec;
-	while (*p && *p != '%')
-	  ++p;
-	pp_wrap_text (pp, text->format_spec, p);
-        text->format_spec = p;
-      }
+      p = text->format_spec;
+      while (*p && *p != '%')
+	++p;
+      pp_wrap_text (pp, text->format_spec, p);
+      text->format_spec = p;
 
       if (*text->format_spec == '\0')
 	break;
 
-      /* We got a '%'.  Check for 'q', then parse precision modifiers,
-	 if any.  */
-      if (*++text->format_spec == 'q')
+      /* We got a '%'.  First check for 'N$'.  */
+      ++text->format_spec;
+      if (*text->format_spec >= '0' && *text->format_spec <= '9')
+	{
+	  char *end;
+	  curarg = strtoul (text->format_spec, &end, 10) - 1;
+	  gcc_assert (*end == '$');
+	  text->format_spec = (const char *) (end + 1);
+	}
+
+      /* Check for 'q', then parse precision modifiers, if any.  */
+      if (*text->format_spec == 'q')
 	{
 	  quoted = true;
 	  ++text->format_spec;
@@ -273,73 +468,81 @@ pp_base_format_text (pretty_printer *pp,
       switch (*text->format_spec)
 	{
 	case 'c':
-	  pp_character (pp, va_arg (*text->args_ptr, int));
+	  pp_character (pp, args[curarg].data.pp_d_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");
+	  if (wide)
+	    pp_wide_integer (pp, args[curarg].data.pp_d_hwi);
+	  else
+	    pp_integer_with_precision
+	      (pp, args, curarg, precision, pp_d_, "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");
+	  if (wide)
+	    pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
+		       args[curarg].data.pp_d_uhwi);
+	  else
+	    pp_integer_with_precision
+	      (pp, args, curarg, precision, pp_d_u, "o");
 	  break;
 
 	case 's':
-	  pp_string (pp, va_arg (*text->args_ptr, const char *));
+	  pp_string (pp, args[curarg].data.pp_d_string);
 	  break;
 
-        case 'p':
-          pp_pointer (pp, va_arg (*text->args_ptr, void *));
-          break;
+	case 'p':
+	  pp_pointer (pp, args[curarg].data.pp_d_ptr);
+	  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");
+	  if (wide)
+	    pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
+		       args[curarg].data.pp_d_uhwi);
+	  else
+	    pp_integer_with_precision
+	      (pp, args, curarg, precision, pp_d_u, "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");
+	  if (wide)
+	    pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
+		       args[curarg].data.pp_d_uhwi);
+	  else
+	    pp_integer_with_precision
+	      (pp, args, curarg, precision, pp_d_u, "x");
 	  break;
 
 	case 'm':
 	  pp_string (pp, xstrerror (text->err_no));
+	  /* Undo ++curarg done by for, as m takes no argument.  */
+	  --curarg;
 	  break;
 
 	case '%':
 	  pp_character (pp, '%');
+	  /* Undo ++curarg done by for, as % takes no argument.  */
+	  --curarg;
 	  break;
 
 	case '<':
 	  pp_string (pp, open_quote);
+	  /* Undo ++curarg done by for, as < takes no argument.  */
+	  --curarg;
 	  break;
 
 	case '>':
 	case '\'':
 	  pp_string (pp, close_quote);
+	  /* Undo ++curarg done by for, as >' take no argument.  */
+	  --curarg;
 	  break;
 
         case 'H':
           {
-            location_t *locus = va_arg (*text->args_ptr, location_t *);
+	    location_t *locus = args[curarg].data.pp_d_locus;
 	    expanded_location s = expand_location (*locus);
             pp_string (pp, "file '");
             pp_string (pp, s.file);
@@ -352,14 +555,32 @@ pp_base_format_text (pretty_printer *pp,
 	  {
 	    int n;
 	    const char *s;
+	    char *end;
 	    /* We handle no precision specifier but '%.*s'.  */
 	    ++text->format_spec;
-	    gcc_assert (*text->format_spec == '*');
-	    ++text->format_spec;
+	    if (*text->format_spec >= '0' && *text->format_spec <= '9')
+	      {
+		n = strtoul (text->format_spec, &end, 10);
+		text->format_spec = (const char *) end;
+	      }
+	    else
+	      {
+		gcc_assert (*text->format_spec == '*');
+		++text->format_spec;
+		if (*text->format_spec >= '0' && *text->format_spec <= '9')
+		  {
+		    n = strtoul (text->format_spec, &end, 10) - 1;
+		    gcc_assert (n >= 0 && n < PP_NL_ARGMAX);
+		    gcc_assert (*end == '$');
+		    text->format_spec = (const char *) (end + 1);
+		    n = args[n].data.pp_d_int;
+		  }
+		else
+		  n = args[curarg++].data.pp_d_int;
+	      }
 	    gcc_assert (*text->format_spec == 's');
 
-	    n = va_arg (*text->args_ptr, int);
-	    s = va_arg (*text->args_ptr, const char *);
+	    s = args[curarg].data.pp_d_string;
 	    pp_append_text (pp, s, s + n);
 	  }
 	  break;
@@ -369,7 +590,7 @@ pp_base_format_text (pretty_printer *pp,
 	    bool ok;
 	    
 	    gcc_assert (pp_format_decoder (pp));
-	    ok = pp_format_decoder (pp) (pp, text);
+	    ok = pp_format_decoder (pp) (pp, text, &args[curarg]);
 	    gcc_assert (ok);
 	  }
 	}
--- gcc/diagnostic.h.jj	2005-05-06 09:58:26.000000000 +0200
+++ gcc/diagnostic.h	2005-05-20 17:58:28.000000000 +0200
@@ -116,6 +116,9 @@ struct diagnostic_context
 /* Extension hook for client.  */
 #define diagnostic_auxiliary_data(DC) (DC)->x_data
 
+/* Same as pp_format_arg_fetch.  Works on 'diagnostic_context *'.  */
+#define diagnostic_format_arg_fetch(DC) ((DC)->printer->format_arg_fetch)
+
 /* Same as pp_format_decoder.  Works on 'diagnostic_context *'.  */
 #define diagnostic_format_decoder(DC) ((DC)->printer->format_decoder)
 
--- gcc/toplev.c.jj	2005-05-06 09:58:28.000000000 +0200
+++ gcc/toplev.c	2005-05-20 18:18:31.000000000 +0200
@@ -1565,23 +1565,41 @@ default_pch_valid_p (const void *data_p,
   }
 }
 
+/* Default tree format argument fetcher.  Handles declarations only.  */
+static bool
+default_tree_arg_fetch (pretty_printer *pp ATTRIBUTE_UNUSED, text_info *text,
+			pp_fmt_arg *arg)
+{
+  switch (arg->code)
+    {
+    case 'D':
+    case 'F':
+    case 'T':
+      arg->data.pp_d_tree = va_arg (*text->args_ptr, tree);
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* Default tree printer.   Handles declarations only.  */
 static bool
-default_tree_printer (pretty_printer * pp, text_info *text)
+default_tree_printer (pretty_printer *pp, text_info *text, pp_fmt_arg *arg)
 {
   tree t;
 
   switch (*text->format_spec)
     {
     case 'D':
-      t = va_arg (*text->args_ptr, tree);
+      t = arg->data.pp_d_tree;
       if (DECL_DEBUG_EXPR (t) && DECL_DEBUG_EXPR_IS_FROM (t))
 	t = DECL_DEBUG_EXPR (t);
       break;
 
     case 'F':
     case 'T':
-      t = va_arg (*text->args_ptr, tree);
+      t = arg->data.pp_d_tree;
       break;
 
     default:
@@ -1626,8 +1644,9 @@ general_init (const char *argv0)
   /* Initialize the diagnostics reporting machinery, so option parsing
      can give warnings and errors.  */
   diagnostic_initialize (global_dc);
-  /* Set a default printer.  Language specific initializations will
-     override it later.  */
+  /* Set a default printer and format arg fetcher.  Language specific
+     initializations will override it later.  */
+  pp_format_arg_fetch (global_dc->printer) = &default_tree_arg_fetch;
   pp_format_decoder (global_dc->printer) = &default_tree_printer;
 
   /* Trap fatal signals, e.g. SIGSEGV, and convert them to ICE messages.  */
--- gcc/c-objc-common.c.jj	2005-04-29 09:17:42.000000000 +0200
+++ gcc/c-objc-common.c	2005-05-20 18:18:31.000000000 +0200
@@ -40,7 +40,8 @@ Software Foundation, 59 Temple Place - S
 #include "target.h"
 #include "c-objc-common.h"
 
-static bool c_tree_printer (pretty_printer *, text_info *);
+static bool c_tree_arg_fetch (pretty_printer *, text_info *, pp_fmt_arg *);
+static bool c_tree_printer (pretty_printer *, text_info *, pp_fmt_arg *);
 
 bool
 c_missing_noreturn_ok_p (tree decl)
@@ -132,6 +133,7 @@ c_objc_common_init (void)
   /* These were not defined in the Objective-C front end, but I'm
      putting them here anyway.  The diagnostic format decoder might
      want an enhanced ObjC implementation.  */
+  diagnostic_format_arg_fetch (global_dc) = &c_tree_arg_fetch;
   diagnostic_format_decoder (global_dc) = &c_tree_printer;
 
   /* If still unspecified, make it match -std=c99
@@ -160,9 +162,26 @@ c_objc_common_init (void)
    Please notice when called, the `%' part was already skipped by the
    diagnostic machinery.  */
 static bool
-c_tree_printer (pretty_printer *pp, text_info *text)
+c_tree_arg_fetch (pretty_printer *pp ATTRIBUTE_UNUSED, text_info *text,
+		  pp_fmt_arg *arg)
 {
-  tree t = va_arg (*text->args_ptr, tree);
+  switch (arg->code)
+    {
+    case 'D':
+    case 'E':
+    case 'F':
+    case 'T':
+      arg->data.pp_d_tree = va_arg (*text->args_ptr, tree);
+      return true;
+    default:
+      return false;
+    }
+}
+
+static bool
+c_tree_printer (pretty_printer *pp, text_info *text, pp_fmt_arg *arg)
+{
+  tree t = arg->data.pp_d_tree;
   tree name;
   const char *n = "({anonymous})";
   c_pretty_printer *cpp = (c_pretty_printer *) pp;
--- gcc/cp/error.c.jj	2005-03-25 11:37:25.000000000 +0100
+++ gcc/cp/error.c	2005-05-20 18:18:31.000000000 +0200
@@ -86,7 +86,8 @@ static void cp_diagnostic_starter (diagn
 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 bool cp_arg_fetch (pretty_printer *, text_info *, pp_fmt_arg *);
+static bool cp_printer (pretty_printer *, text_info *, pp_fmt_arg *);
 static tree locate_error (const char *, va_list);
 static location_t location_of (tree);
 
@@ -95,6 +96,7 @@ init_error (void)
 {
   diagnostic_starter (global_dc) = cp_diagnostic_starter;
   diagnostic_finalizer (global_dc) = cp_diagnostic_finalizer;
+  diagnostic_format_arg_fetch (global_dc) = cp_arg_fetch;
   diagnostic_format_decoder (global_dc) = cp_printer;
 
   pp_construct (pp_base (cxx_pp), NULL, 0);
@@ -2272,14 +2274,48 @@ print_instantiation_context (void)
    %T   type.
    %V   cv-qualifier.  */
 static bool
-cp_printer (pretty_printer *pp, text_info *text)
+cp_arg_fetch (pretty_printer *pp ATTRIBUTE_UNUSED, text_info *text,
+	      pp_fmt_arg *arg)
+{
+#define next_tree    arg->data.pp_d_tree = va_arg (*text->args_ptr, tree)
+#define next_tcode   arg->data.pp_d_int \
+		       = (int) va_arg (*text->args_ptr, enum tree_code)
+#define next_lang    arg->data.pp_d_int \
+		       = (int) va_arg (*text->args_ptr, enum languages)
+#define next_int     arg->data.pp_d_int = va_arg (*text->args_ptr, int)
+
+  switch (arg->code)
+    {
+    case 'A': next_tree; break;
+    case 'C': next_tcode; break;
+    case 'D': next_tree; break;
+    case 'E': next_tree; break;
+    case 'F': next_tree; break;
+    case 'L': next_lang; break;
+    case 'O': next_tcode; break;
+    case 'P': next_int; break;
+    case 'Q': next_tcode; break;
+    case 'T': next_tree; break;
+    case 'V': next_tree; break;
+    default:
+      return false;
+    }
+  return true;
+#undef next_tree
+#undef next_tcode
+#undef next_lang
+#undef next_int
+}
+
+static bool
+cp_printer (pretty_printer *pp, text_info *text, pp_fmt_arg *arg)
 {
   int verbose = 0;
   const char *result;
-#define next_tree    va_arg (*text->args_ptr, tree)
-#define next_tcode   va_arg (*text->args_ptr, enum tree_code)
-#define next_lang    va_arg (*text->args_ptr, enum languages)
-#define next_int     va_arg (*text->args_ptr, int)
+#define next_tree    arg->data.pp_d_tree
+#define next_tcode   ((enum tree_code) arg->data.pp_d_int)
+#define next_lang    ((enum languages) arg->data.pp_d_int)
+#define next_int     arg->data.pp_d_int
 
   if (*text->format_spec == '+')
     ++text->format_spec;


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]