re PR c++/24985 (caret diagnostics)
authorManuel López-Ibáñez <manu@gcc.gnu.org>
Wed, 11 Apr 2012 09:26:48 +0000 (09:26 +0000)
committerManuel López-Ibáñez <manu@gcc.gnu.org>
Wed, 11 Apr 2012 09:26:48 +0000 (09:26 +0000)
2012-04-11  Manuel López-Ibáñez  <manu@gcc.gnu.org>

PR 24985
gcc/
        * diagnostic.h (show_caret): Declare.
(caret_max_width): Declare.
(diagnostic_show_locus): Declare.
        * diagnostic.c (diagnostic_initialize): Initialize to false.
        (diagnostic_show_locus): New.
        (diagnostic_report_diagnostic): Call it.
(getenv_columns): New.
(adjust_line): New.
(diagnostic_set_caret_max_width): New.
        * input.c (read_line): New.
(location_get_source_line): New.
        * input.h (location_get_source_line): Declare.
        * toplev.c (general_init): Initialize show_caret from options.
        * dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret.
        * opts.c (common_handle_option): Likewise.
* pretty-print.h (pp_get_prefix): New.
(pp_base_get_prefix): New.
        * common.opt (fdiagnostics-show-caret): New option.
* doc/invoke.texi (fdiagnostics-show-caret): Document it.
testsuite/
        * lib/prune.exp: Add -fno-diagnostics-show-caret.
libstdc++-v3/
* testsuite/lib/prune.exp: Handle caret.
libmudflap/
* testsuite/lib/libmudflap.exp: Handle caret.

From-SVN: r186305

17 files changed:
gcc/ChangeLog
gcc/common.opt
gcc/diagnostic.c
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/dwarf2out.c
gcc/input.c
gcc/input.h
gcc/opts.c
gcc/pretty-print.h
gcc/testsuite/ChangeLog
gcc/testsuite/lib/prune.exp
gcc/toplev.c
libmudflap/ChangeLog
libmudflap/testsuite/lib/libmudflap.exp
libstdc++-v3/ChangeLog
libstdc++-v3/testsuite/lib/prune.exp

index 62a4e88372400e1577175dab92e39b05bc9d9b5d..b4a02ddde5b669a05375f244b0f3415fb5a7f50a 100644 (file)
@@ -1,3 +1,26 @@
+2012-04-11  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR 24985
+        * diagnostic.h (show_caret): Declare.
+       (caret_max_width): Declare.
+       (diagnostic_show_locus): Declare.
+        * diagnostic.c (diagnostic_initialize): Initialize to false.
+        (diagnostic_show_locus): New.
+        (diagnostic_report_diagnostic): Call it.
+       (getenv_columns): New.
+       (adjust_line): New.
+       (diagnostic_set_caret_max_width): New.
+        * input.c (read_line): New.
+       (location_get_source_line): New.
+        * input.h (location_get_source_line): Declare.
+        * toplev.c (general_init): Initialize show_caret from options.
+        * dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret.
+        * opts.c (common_handle_option): Likewise.
+       * pretty-print.h (pp_get_prefix): New.
+       (pp_base_get_prefix): New.
+        * common.opt (fdiagnostics-show-caret): New option.
+       * doc/invoke.texi (fdiagnostics-show-caret): Document it.
+
 2012-04-11  Richard Guenther  <rguenther@suse.de>
 
        PR rtl-optimization/52881
index 98fa2bb6cca017b28a6e02611101fe74476e3ee1..39f1679ab1a83a2f2533a280313bedd3d817241e 100644 (file)
@@ -999,6 +999,10 @@ Enum(diagnostic_prefixing_rule) String(once) Value(DIAGNOSTICS_SHOW_PREFIX_ONCE)
 EnumValue
 Enum(diagnostic_prefixing_rule) String(every-line) Value(DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE)
 
+fdiagnostics-show-caret
+Common Var(flag_diagnostics_show_caret) Init(1)
+Show the source line with a caret indicating the column
+
 fdiagnostics-show-option
 Common Var(flag_diagnostics_show_option) Init(1)
 Amend appropriate diagnostic messages with the command line option that controls them
index a68d6ce88eed9c17752dc68d99c461dfea9ae6d3..60773d3ac505dd257e60ccf657af63fa92f14503 100644 (file)
@@ -78,6 +78,35 @@ file_name_as_prefix (const char *f)
 
 
 \f
+/* Return the value of the getenv("COLUMNS") as an integer. If the
+   value is not set to a positive integer, then return INT_MAX.  */
+static int
+getenv_columns (void)
+{
+  const char * s = getenv ("COLUMNS");
+  if (s != NULL) {
+    int n = atoi (s);
+    if (n > 0)
+      return n;
+  }
+  return INT_MAX;
+}
+
+/* Set caret_max_width to value.  */
+void
+diagnostic_set_caret_max_width (diagnostic_context *context, int value)
+{
+  /* One minus to account for the leading empty space.  */
+  value = value ? value - 1 
+    : (isatty (fileno (context->printer->buffer->stream))
+       ? getenv_columns () - 1: INT_MAX);
+  
+  if (value <= 0) 
+    value = INT_MAX;
+
+  context->caret_max_width = value;
+}
+
 /* Initialize the diagnostic message outputting machinery.  */
 void
 diagnostic_initialize (diagnostic_context *context, int n_opts)
@@ -100,6 +129,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   context->classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
   for (i = 0; i < n_opts; i++)
     context->classify_diagnostic[i] = DK_UNSPECIFIED;
+  context->show_caret = false;
+  diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
   context->show_option_requested = false;
   context->abort_on_error = false;
   context->show_column = false;
@@ -196,6 +227,72 @@ diagnostic_build_prefix (diagnostic_context *context,
      : build_message_string ("%s:%d: %s", s.file, s.line, text));
 }
 
+/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
+   MAX_WIDTH by some margin, then adjust the start of the line such
+   that the COLUMN is smaller than MAX_WIDTH minus the margin.  The
+   margin is either 10 characters or the difference between the column
+   and the length of the line, whatever is smaller.  */
+static const char *
+adjust_line (const char *line, int max_width, int *column_p)
+{
+  int right_margin = 10;
+  int line_width = strlen (line);
+  int column = *column_p;
+
+  right_margin = MIN(line_width - column, right_margin);
+  right_margin = max_width - right_margin;
+  if (line_width >= max_width && column > right_margin)
+    {
+      line += column - right_margin;
+      *column_p = right_margin;
+    }
+  return line;
+}
+
+/* Print the physical source line corresponding to the location of
+   this diagnostics, and a caret indicating the precise column.  */
+void
+diagnostic_show_locus (diagnostic_context * context,
+                      const diagnostic_info *diagnostic)
+{
+  const char *line;
+  char *buffer;
+  expanded_location s;
+  int max_width;
+  const char *saved_prefix;
+
+
+  if (!context->show_caret
+      || diagnostic->location <= BUILTINS_LOCATION)
+    return;
+
+  s = expand_location(diagnostic->location);
+  line = location_get_source_line (s);
+  if (line == NULL)
+    return;
+
+  max_width = context->caret_max_width;
+  line = adjust_line (line, max_width, &(s.column));
+
+  pp_newline (context->printer);
+  saved_prefix = pp_get_prefix (context->printer);
+  pp_set_prefix (context->printer, NULL);
+  pp_character (context->printer, ' ');
+  while (max_width > 0 && *line != '\0')
+    {
+      char c = *line == '\t' ? ' ' : *line;
+      pp_character (context->printer, c);
+      max_width--;
+      line++;
+    }
+  pp_newline (context->printer);
+  /* pp_printf does not implement %*c.  */
+  buffer = XALLOCAVEC (char, s.column + 3);
+  snprintf (buffer, s.column + 3, " %*c", s.column, '^');
+  pp_string (context->printer, buffer);
+  pp_set_prefix (context->printer, saved_prefix);
+}
+
 /* Take any action which is expected to happen after the diagnostic
    is written out.  This function does not always return.  */
 static void
@@ -547,6 +644,7 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   pp_format (context->printer, &diagnostic->message);
   (*diagnostic_starter (context)) (context, diagnostic);
   pp_output_formatted_text (context->printer);
+  diagnostic_show_locus (context, diagnostic);
   (*diagnostic_finalizer (context)) (context, diagnostic);
   pp_flush (context->printer);
   diagnostic_action_after_output (context, diagnostic);
index 4b1265b78868e3f995f8dd67e79a81b6636b1bab..63eb38529588ff801134ee6574dffc2727728f42 100644 (file)
@@ -99,6 +99,13 @@ struct diagnostic_context
   int *push_list;
   int n_push;
 
+  /* True if we should print the source line with a caret indicating
+     the location.  */
+  bool show_caret;
+
+  /* Maximum width of the source line printed.  */
+  int caret_max_width;
+
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
   bool show_option_requested;
@@ -254,6 +261,7 @@ extern diagnostic_context *global_dc;
 extern void diagnostic_initialize (diagnostic_context *, int);
 extern void diagnostic_finish (diagnostic_context *);
 extern void diagnostic_report_current_module (diagnostic_context *, location_t);
+extern void diagnostic_show_locus (diagnostic_context *, const diagnostic_info *);
 
 /* Force diagnostics controlled by OPTIDX to be kind KIND.  */
 extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *,
@@ -275,6 +283,8 @@ extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
 extern char *diagnostic_build_prefix (diagnostic_context *, diagnostic_info *);
 void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
 void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
+void diagnostic_set_caret_max_width (diagnostic_context *context, int value);
+
 
 /* Pure text formatting support functions.  */
 extern char *file_name_as_prefix (const char *);
index cf6c9f238447749c8fb2641ca7c02534a1200bc3..2dde9c74147d1524c0dec0d4a2ad769ff16af206 100644 (file)
@@ -230,7 +230,7 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Language Independent Options,,Options to Control Diagnostic Messages Formatting}.
 @gccoptlist{-fmessage-length=@var{n}  @gol
 -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
--fno-diagnostics-show-option}
+-fno-diagnostics-show-option -fno-diagnostics-show-caret}
 
 @item Warning Options
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
@@ -2894,6 +2894,13 @@ command-line option that directly controls the diagnostic (if such an
 option is known to the diagnostic machinery).  Specifying the
 @option{-fno-diagnostics-show-option} flag suppresses that behavior.
 
+@item -fno-diagnostics-show-caret
+@opindex fno-diagnostics-show-caret
+@opindex fdiagnostics-show-caret
+By default, each diagnostic emitted includes the original source line
+and a caret '^' indicating the column.  This option suppresses this
+information.
+
 @end table
 
 @node Warning Options
index ca88fc56b10b2c7fb0295a4021022b750935ed70..7e2ce58ae4519828859aa3c75366120f9a8c0e13 100644 (file)
@@ -18369,6 +18369,7 @@ gen_producer_string (void)
       case OPT__output_pch_:
       case OPT_fdiagnostics_show_location_:
       case OPT_fdiagnostics_show_option:
+      case OPT_fdiagnostics_show_caret:
       case OPT_fverbose_asm:
       case OPT____:
       case OPT__sysroot_:
index 4077f9e5dbdff9d316a3dc1069594de4a0d499dc..bf5fe481fdfdb6054068588907da4df29d7d8d88 100644 (file)
@@ -50,6 +50,65 @@ expand_location (source_location loc)
   return xloc;
 }
 
+/* Reads one line from file into a static buffer.  */
+static const char *
+read_line (FILE *file)
+{
+  static char *string;
+  static size_t string_len;
+  size_t pos = 0;
+  char *ptr;
+
+  if (!string_len)
+    {
+      string_len = 200;
+      string = XNEWVEC (char, string_len);
+    }
+
+  while ((ptr = fgets (string + pos, string_len - pos, file)))
+    {
+      size_t len = strlen (string + pos);
+
+      if (string[pos + len - 1] == '\n')
+       {
+         string[pos + len - 1] = 0;
+         return string;
+       }
+      pos += len;
+      ptr = XNEWVEC (char, string_len * 2);
+      if (ptr)
+       {
+         memcpy (ptr, string, pos);
+         string = ptr;
+         string_len += 2;
+       }
+      else
+       pos = 0;
+    }
+      
+  return pos ? string : NULL;
+}
+
+/* Return the physical source line that corresponds to xloc in a
+   buffer that is statically allocated.  The newline is replaced by
+   the null character.  */
+
+const char *
+location_get_source_line(expanded_location xloc)
+{
+  const char *buffer;
+  int lines = 1;
+  FILE *stream = xloc.file ? fopen (xloc.file, "r") : NULL;
+  if (!stream)
+    return NULL;
+
+  while ((buffer = read_line (stream)) && lines < xloc.line)
+    lines++;
+
+  fclose (stream);
+  return buffer;
+}
+
 #define ONE_K 1024
 #define ONE_M (ONE_K * ONE_K)
 
index f2f351311fcc1843858616e7767ef43d0fa76b18..4b152228fc40934252ff7721f65f76ad3c36f912 100644 (file)
@@ -38,6 +38,7 @@ extern char builtins_location_check[(BUILTINS_LOCATION
                                     < RESERVED_LOCATION_COUNT) ? 1 : -1];
 
 extern expanded_location expand_location (source_location);
+extern const char * location_get_source_line(expanded_location xloc);
 
 /* Historically GCC used location_t, while cpp used source_location.
    This could be removed but it hardly seems worth the effort.  */
index 6532b56d75289991c36d69b0f29243f2e2d0fc42..4e8b3c033fee06fbb105689d4e75305b50e94e36 100644 (file)
@@ -1499,6 +1499,10 @@ common_handle_option (struct gcc_options *opts,
     case OPT_fdiagnostics_show_location_:
       diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value;
       break;
+    case OPT_fdiagnostics_show_caret:
+      dc->show_caret = value;
+      break;
 
     case OPT_fdiagnostics_show_option:
       dc->show_option_requested = value;
@@ -1539,6 +1543,7 @@ common_handle_option (struct gcc_options *opts,
 
     case OPT_fmessage_length_:
       pp_set_line_maximum_length (dc->printer, value);
+      diagnostic_set_caret_max_width (dc, value);
       break;
 
     case OPT_fpack_struct_:
index bb1d156d31dd91b0de20f76d473cf33b155d5e36..a7b5a9fbbbad90c61e13b1673400decc0ee16eed 100644 (file)
@@ -201,6 +201,9 @@ struct pretty_print_info
 #define pp_set_line_maximum_length(PP, L) \
    pp_base_set_line_maximum_length (pp_base (PP), L)
 #define pp_set_prefix(PP, P)    pp_base_set_prefix (pp_base (PP), P)
+#define pp_get_prefix(PP)       pp_base_get_prefix (pp_base (PP))
+static inline const char *
+pp_base_get_prefix (const pretty_printer *pp) { return pp->prefix; }
 #define pp_destroy_prefix(PP)   pp_base_destroy_prefix (pp_base (PP))
 #define pp_remaining_character_count_for_line(PP) \
   pp_base_remaining_character_count_for_line (pp_base (PP))
index 7176e6a1f752e63e1d80d046fc711a9691c612c5..61d83ffeedc5d0918fbe102f2e05c32a70782f5b 100644 (file)
@@ -1,3 +1,8 @@
+2012-04-11  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR 24985
+        * lib/prune.exp: Add -fno-diagnostics-show-caret.
+
 2012-04-11  Richard Guenther  <rguenther@suse.de>
 
        PR rtl-optimization/52881
index 68a77b6ac48a3f71229728a3198e7519ac33a579..d2ba49e9db04335844002a227d5d99c5344f4ba8 100644 (file)
@@ -17,6 +17,8 @@
 
 # Prune messages from gcc that aren't useful.
 
+set TEST_ALWAYS_FLAGS "-fno-diagnostics-show-caret $TEST_ALWAYS_FLAGS"
+
 proc prune_gcc_output { text } {
     #send_user "Before:$text\n"
 
index e01ed8141001d02a5795497988878c1ef39ad8be..51d52e1c8dd77bb6feb1f54d74dd32c9a9b18aa1 100644 (file)
@@ -1169,6 +1169,8 @@ general_init (const char *argv0)
   /* Set a default printer.  Language specific initializations will
      override it later.  */
   pp_format_decoder (global_dc->printer) = &default_tree_printer;
+  global_dc->show_caret
+    = global_options_init.x_flag_diagnostics_show_caret;
   global_dc->show_option_requested
     = global_options_init.x_flag_diagnostics_show_option;
   global_dc->show_column
index 3d3e5af21a93934a45b4d43326071ce9d995e67d..9fb1cac7758b2cfad75fe5906655138551447769 100644 (file)
@@ -1,3 +1,8 @@
+2012-04-11  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR 24985
+       * testsuite/lib/libmudflap.exp: Handle caret.
+
 2012-01-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR libmudflap/40778
index f9603553199cdc7d2b2a5e5d7b89856286cce2fd..00699e87b756a84e76099eeb3502f95b6ae91451 100644 (file)
@@ -298,6 +298,9 @@ proc libmudflap-dg-prune { system text } {
 
 
 proc prune_gcc_output { text } {
+    # Ignore caret diagnostics. Unfortunately dejaGNU trims leading
+    # spaces, so one cannot rely on them being present.
+    regsub -all "(^|\n)\[^\n\]+\n *\\^\n" $text "\n" text
     regsub -all {(^|\n)[^\n]*ld: warning: libgcc_s[^\n]*not found[^\n]*try using[^\n]*} $text "" text
     regsub -all {(^|\n)[^\n]*In function.*pthread_create[^\n]*} $text "" text
     regsub -all {(^|\n)[^\n]*the use of .pthread.*is deprecated[^\n]*} $text "" text
index 9bd426812e7f4c7ee00576a26d1b8d8796ee2931..ba608fec0351b5d94dc918a400db71bcb8c1d91f 100644 (file)
@@ -1,3 +1,8 @@
+2012-04-11  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR 24985
+       * testsuite/lib/prune.exp: Handle caret.
+
 2012-04-05  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        Partially revert:
index a5644061d2367c9997beaf0f89510270e8ebacf9..a2371c60d5fe77d4697ab4977abe97d9b795bfba 100644 (file)
@@ -32,6 +32,12 @@ proc dg-prune-output { args } {
 proc libstdc++-dg-prune { system text } {
     global additional_prunes
 
+#    send_user "Before:$text\n"
+
+    # Ignore caret diagnostics. Unfortunately dejaGNU trims leading
+    # spaces, so one cannot rely on them being present.
+    regsub -all "(^|\n)\[^\n\]+\n *\\^\n" $text "\n" text
+
     # Cygwin warns about -ffunction-sections
     regsub -all "(^|\n)\[^\n\]*: -ffunction-sections may affect debugging on some targets\[^\n\]*" $text "" text
 
@@ -68,5 +74,6 @@ proc libstdc++-dg-prune { system text } {
        }
     }
 
+#    send_user "After:$text\n"
     return $text
 }