public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Caret diagnostics
@ 2012-04-06  8:12 Manuel López-Ibáñez
  2012-04-06 13:42 ` Mike Stump
  2012-04-06 22:04 ` Jason Merrill
  0 siblings, 2 replies; 66+ messages in thread
From: Manuel López-Ibáñez @ 2012-04-06  8:12 UTC (permalink / raw)
  To: Gcc Patch List; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1290 bytes --]

A simple implementation of caret diagnostics.

In the testsuite, pruning the caret output does not always work
because of several known deficiencies of DejaGNU, thus in some places
I disable the caret explicitly.

Bootstrapped and regression tested on x86_64-unknown-gnu-linux with
enable-languages=all,ada and -m32/-m64.

OK to commit?


2012-04-05  Manuel López-Ibáñez  <manu@gcc.gnu.org>

	PR 24985
libstdc++-v3/
	* testsuite/lib/prune.exp: Handle caret.
libmudflap/
	* testsuite/lib/libmudflap.exp: Handle caret.
gcc/
        * diagnostic.h (show_caret): Declare.
        * diagnostic.c (diagnostic_initialize): Initialize to false.
        (diagnostic_show_locus): New.
        (diagnostic_report_diagnostic): Call it.
        * 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.
        * testsuite/lib/prune.exp: Add -fno-diagnostics-show-caret.
        * testsuite/gcc.dg/torture/tls/tls.exp: Add -fno-diagnostics-show-caret.
        * dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret.
        * opts.c (common_handle_option): Likewise.
        * common.opt (fdiagnostics-show-caret): New option.

[-- Attachment #2: caret-diagnostics-20120406.diff --]
[-- Type: application/octet-stream, Size: 12577 bytes --]

Index: libstdc++-v3/testsuite/lib/prune.exp
===================================================================
--- libstdc++-v3/testsuite/lib/prune.exp	(revision 186103)
+++ libstdc++-v3/testsuite/lib/prune.exp	(working copy)
@@ -30,10 +30,18 @@ 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
+    # Also it may trim a source line by mistake since it matches repeated lines.
+    regsub -all "(^|\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
 
     # Remove parts of warnings that refer to location of previous
     # definitions, etc as these confuse dejagnu
@@ -66,7 +74,8 @@ proc libstdc++-dg-prune { system text } 
 	    # Following regexp matches a complete line containing $p.
 	    regsub -all "(^|\n)\[^\n\]*$p\[^\n\]*" $text "" text
 	}
     }
 
+#    send_user "After:$text\n"
     return $text
 }
Index: libmudflap/testsuite/lib/libmudflap.exp
===================================================================
--- libmudflap/testsuite/lib/libmudflap.exp	(revision 186103)
+++ libmudflap/testsuite/lib/libmudflap.exp	(working copy)
@@ -296,10 +296,15 @@ proc libmudflap-dg-prune { system text }
     return $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
+    # Also it may trim a source line by mistake since it matches repeated lines.
+    regsub -all "(^|\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
     regsub -all {(^|\n)[^\n]*Dwarf Error:.*FORM value: 14[^\n]*} $text "" text
     regsub -all {(^|\n)[^\n]*In function[^\n]*} $text "" text
Index: gcc/diagnostic.c
===================================================================
--- gcc/diagnostic.c	(revision 186103)
+++ gcc/diagnostic.c	(working copy)
@@ -98,10 +98,11 @@ diagnostic_initialize (diagnostic_contex
   context->warning_as_error_requested = false;
   context->n_opts = 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;
   context->show_option_requested = false;
   context->abort_on_error = false;
   context->show_column = false;
   context->pedantic_errors = false;
   context->permissive = false;
@@ -194,10 +195,67 @@ diagnostic_build_prefix (diagnostic_cont
      : context->show_column
      ? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text)
      : build_message_string ("%s:%d: %s", s.file, s.line, text));
 }
 
+/* Print the physical source line corresponding to the location of
+   this diagnostics, and a caret indicating the precise column.  */
+static void
+diagnostic_show_locus (diagnostic_context * context,
+		       diagnostic_info *diagnostic)
+{
+  const char *line;
+  expanded_location s;
+  int k, real_width, real_column;
+  int max_width = 80, right_margin = 10;
+
+  if (!context->show_caret
+      || diagnostic->location <= BUILTINS_LOCATION)
+    return;
+
+  s = expand_location(diagnostic->location);
+  line = location_get_source_line (s);
+  if (line == NULL)
+    return;
+
+  for (k = real_column = 0; k < s.column && line[k] != '\0'; k++)
+    real_column += (line[k] == '\t') ? 8 : 1;
+
+  for (real_width = real_column; line[k] != '\0'; k++)
+    real_width += (line[k] == '\t') ? 8 : 1;
+
+  /* If the line is longer than max_width and the column is too close
+     to max_width, skip part of the line until it is not so close.  */
+  right_margin = max_width - right_margin;
+  if (real_width >= max_width && real_column > right_margin) {
+    for (k = real_column - right_margin; k > 0; line++)
+      {
+	k -= (*line == '\t') ? 8 : 1;
+      }
+    real_column = right_margin + k;
+  }
+
+  fputc (' ', stderr);
+  while (max_width > 0 && *line != '\0')
+    {
+      if (*line != '\t')
+	{
+	  max_width--;
+	  fputc (*line, stderr);
+	} 
+      else 
+	{
+	  /* TABs are 8 spaces.  */
+	  max_width -= 8;
+	  fputs ("        ", stderr);
+	}
+      line++;
+    }
+  fputc ('\n', stderr);
+  fprintf (stderr, " %*c\n", real_column, '^');
+}
+
 /* Take any action which is expected to happen after the diagnostic
    is written out.  This function does not always return.  */
 static void
 diagnostic_action_after_output (diagnostic_context *context,
 				diagnostic_info *diagnostic)
@@ -547,10 +605,11 @@ diagnostic_report_diagnostic (diagnostic
   pp_format (context->printer, &diagnostic->message);
   (*diagnostic_starter (context)) (context, diagnostic);
   pp_output_formatted_text (context->printer);
   (*diagnostic_finalizer (context)) (context, diagnostic);
   pp_flush (context->printer);
+  diagnostic_show_locus (context, diagnostic);
   diagnostic_action_after_output (context, diagnostic);
   diagnostic->message.format_spec = saved_format_spec;
   diagnostic->x_data = NULL;
 
   context->lock--;
Index: gcc/diagnostic.h
===================================================================
--- gcc/diagnostic.h	(revision 186103)
+++ gcc/diagnostic.h	(working copy)
@@ -97,10 +97,14 @@ struct diagnostic_context
 
   /* For pragma push/pop.  */
   int *push_list;
   int n_push;
 
+  /* True if we should print the source line with a caret indicating
+     the location.  */
+  bool show_caret;
+
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
   bool show_option_requested;
 
   /* True if we should raise a SIGABRT on errors.  */
Index: gcc/input.c
===================================================================
--- gcc/input.c	(revision 186103)
+++ gcc/input.c	(working copy)
@@ -48,10 +48,69 @@ expand_location (source_location loc)
     xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
 
   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)
 
 /* Display a number as an integer multiple of either:
    - 1024, if said integer is >= to 10 K (in base 2)
Index: gcc/input.h
===================================================================
--- gcc/input.h	(revision 186103)
+++ gcc/input.h	(working copy)
@@ -36,10 +36,11 @@ extern GTY(()) struct line_maps *line_ta
    both UNKNOWN_LOCATION and BUILTINS_LOCATION fit into that.  */
 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.  */
 typedef source_location location_t;
 
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 186103)
+++ gcc/toplev.c	(working copy)
@@ -1167,10 +1167,12 @@ general_init (const char *argv0)
      finalizer -- for tokens resulting from macro macro expansion.  */
   diagnostic_finalizer (global_dc) = virt_loc_aware_diagnostic_finalizer;
   /* 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
     = global_options_init.x_flag_show_column;
   global_dc->internal_error = plugins_internal_error_function;
Index: gcc/testsuite/lib/prune.exp
===================================================================
--- gcc/testsuite/lib/prune.exp	(revision 186103)
+++ gcc/testsuite/lib/prune.exp	(working copy)
@@ -15,10 +15,12 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
 # 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"
 
     regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
Index: gcc/testsuite/gcc.dg/torture/tls/tls.exp
===================================================================
--- gcc/testsuite/gcc.dg/torture/tls/tls.exp	(revision 186103)
+++ gcc/testsuite/gcc.dg/torture/tls/tls.exp	(working copy)
@@ -48,10 +48,10 @@ dg-init
 torture-init
 set-torture-options $TLS_TORTURE_OPTIONS {{}} $LTO_TORTURE_OPTIONS
 
 # Main loop.
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
-        $DEFAULT_CFLAGS
+        "-fno-diagnostics-show-caret $DEFAULT_CFLAGS"
 
 # All done.
 torture-finish
 dg-finish
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 186103)
+++ gcc/dwarf2out.c	(working copy)
@@ -18367,10 +18367,11 @@ gen_producer_string (void)
       case OPT_grecord_gcc_switches:
       case OPT_gno_record_gcc_switches:
       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_:
       case OPT_nostdinc:
       case OPT_nostdinc__:
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 186103)
+++ gcc/opts.c	(working copy)
@@ -1497,10 +1497,14 @@ common_handle_option (struct gcc_options
       break;
 
     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;
       break;
 
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 186103)
+++ gcc/common.opt	(working copy)
@@ -997,10 +997,14 @@ EnumValue
 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
 
 fdisable-

^ permalink raw reply	[flat|nested] 66+ messages in thread
* [PATCH] caret diagnostics (was: broken FE diagnostics wrt complex expressions)
@ 2008-08-14 12:12 Manuel López-Ibáñez
  2008-08-14 12:41 ` Joseph S. Myers
  2008-08-14 18:00 ` Tom Tromey
  0 siblings, 2 replies; 66+ messages in thread
From: Manuel López-Ibáñez @ 2008-08-14 12:12 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Aldy Hernandez, dberlin, jakub, gcc, gdr, Chris Lattner, Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 1930 bytes --]

2008/8/14 Tom Tromey <tromey@redhat.com>:
>
> ISTR Manuel having a patch for caret diagnostic output... ?
>

I was planning to submit it this week to consider it for GCC 4.4
(disabled by default). I am still testing it. Bootstrap and regression
testing with --enable-languages=all,ada,obj-c++ is very slow even on a
x86_64-unknown-gnu-linux-pc.  But here it is for your reviewing and
testing pleasure. ;-)

The approach followed is to never free the input buffers and keep
pointers to the start of each line tracked by each line-map.

Alternative approaches are:

b) Re-open the file and fseek but that is not trivial since we need to
do it fast but still do all character conversions that we did when
libcpp opened it the first time. This is approximately what clang does
as far as I know except that they keep a cache of buffers ever
reopened. I think that thanks to our line-maps implementation, we can
do the seeking quite more efficiently in terms of computation time.
Still I do not know how to *properly* and *efficiently* re-open a
file.

c) Memcpy the relevant lines to a buffer for each line_map. This does
not seem a good approach under any circumstance. It means more memory
needed while the input buffers are opened (because we will end up with
two copies of the buffer) and we cannot free up that memory later
because we do not track how many references there are to each
line_maps, so we never free them. Perhaps the GC can help here? This
is the approach followed by GFortran.

Comments are welcome. However, I don't have time to do
memory/computation time tests (setting up the environment itself seems
very time consuming), so those would be *greatly* appreciated!

You can see many examples of the caret output by configuring with
--enable-caret-diagnostics, then reverting the changes to
gcc/testsuite/lib/gcc.exp and running the testsuite. Check the output
in the gcc.log and g++.log files.

Cheers,

Manuel.

[-- Attachment #2: caret-diagnostics-20080814.diff --]
[-- Type: text/plain, Size: 38186 bytes --]

Index: gcc/java/jcf-parse.c
===================================================================
--- gcc/java/jcf-parse.c	(revision 138935)
+++ gcc/java/jcf-parse.c	(working copy)
@@ -1193,12 +1193,14 @@ give_name_to_class (JCF *jcf, int i)
 					    JPOOL_UTF_LENGTH (jcf, j));
       this_class = lookup_class (class_name);
       {
       tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
       const char *sfname = find_sourcefile (IDENTIFIER_POINTER (source_name));
-      linemap_add (line_table, LC_ENTER, false, sfname, 0);
-      input_location = linemap_line_start (line_table, 0, 1);
+      /* FIXME CARET: We should add a pointer to the input line
+	 instead of NULL.  */
+      linemap_add (line_table, LC_ENTER, false, sfname, 0, NULL);
+      input_location = linemap_line_start (line_table, 0, 1, NULL);
       file_start_location = input_location;
       DECL_SOURCE_LOCATION (TYPE_NAME (this_class)) = input_location;
       if (main_input_filename == NULL && jcf == main_jcf)
 	main_input_filename = sfname;
       }
@@ -1472,11 +1474,11 @@ jcf_parse (JCF* jcf)
     fatal_error ("error while parsing final attributes");
 
   if (TYPE_REFLECTION_DATA (current_class))
     annotation_write_byte (JV_DONE_ATTR);
 
-  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0, NULL);
 
   /* The fields of class_type_node are already in correct order. */
   if (current_class != class_type_node && current_class != object_type_node)
     TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class));
 
@@ -1505,12 +1507,12 @@ load_inner_classes (tree cur_class)
 
 static void
 duplicate_class_warning (const char *filename)
 {
   location_t warn_loc;
-  linemap_add (line_table, LC_RENAME, 0, filename, 0);
-  warn_loc = linemap_line_start (line_table, 0, 1);
+  linemap_add (line_table, LC_RENAME, 0, filename, 0, NULL);
+  warn_loc = linemap_line_start (line_table, 0, 1, NULL);
   warning (0, "%Hduplicate class will only be compiled once", &warn_loc);
 }
 
 static void
 java_layout_seen_class_methods (void)
@@ -1558,11 +1560,11 @@ parse_class_file (void)
 
   input_location = DECL_SOURCE_LOCATION (TYPE_NAME (current_class));
   {
     /* Re-enter the current file.  */
     expanded_location loc = expand_location (input_location);
-    linemap_add (line_table, LC_ENTER, 0, loc.file, loc.line);
+    linemap_add (line_table, LC_ENTER, 0, loc.file, loc.line, NULL);
   }
   file_start_location = input_location;
   (*debug_hooks->start_source_file) (input_line, input_filename);
 
   java_mark_class_local (current_class);
@@ -1625,11 +1627,11 @@ parse_class_file (void)
 	       * Needs to be set before init_function_start. */
 	      if (min_line == 0 || line < min_line)
 		min_line = line;
 	    }
 	  if (min_line != 0)
-	    input_location = linemap_line_start (line_table, min_line, 1);
+	    input_location = linemap_line_start (line_table, min_line, 1, NULL);
 	}
       else
 	{
 	  linenumber_table = NULL;
 	  linenumber_count = 0;
@@ -1897,18 +1899,18 @@ java_parse_file (int set_yydebug ATTRIBU
 	{
 	  main_jcf = GGC_NEW (JCF);
 	  JCF_ZERO (main_jcf);
 	  main_jcf->read_state = finput;
 	  main_jcf->filbuf = jcf_filbuf_from_stdio;
-	  linemap_add (line_table, LC_ENTER, false, filename, 0);
-	  input_location = linemap_line_start (line_table, 0, 1);
+	  linemap_add (line_table, LC_ENTER, false, filename, 0, NULL);
+	  input_location = linemap_line_start (line_table, 0, 1, NULL);
 	  if (open_in_zip (main_jcf, filename, NULL, 0) <  0)
 	    fatal_error ("bad zip/jar file %s", filename);
 	  localToFile = SeenZipFiles;
 	  /* Register all the classes defined there.  */
 	  process_zip_dir ((FILE *) main_jcf->read_state);
-	  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+	  linemap_add (line_table, LC_LEAVE, false, NULL, 0, NULL);
 	  parse_zip_file_entries ();
 	}
       else if (magic == (JCF_u4) ZIPEMPTYMAGIC)
 	{
 	  /* Ignore an empty input jar.  */
@@ -1921,11 +1923,11 @@ java_parse_file (int set_yydebug ATTRIBU
 	  java_parser_context_save_global ();
 
 	  parse_source_file_1 (real_file, filename, finput);
 	  java_parser_context_restore_global ();
 	  java_pop_parser_context (1);
-	  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+	  linemap_add (line_table, LC_LEAVE, false, NULL, 0, NULL);
 #endif
 	}
     }
 
   for (node = current_file_list; node; node = TREE_CHAIN (node))
Index: gcc/java/expr.c
===================================================================
--- gcc/java/expr.c	(revision 138935)
+++ gcc/java/expr.c	(working copy)
@@ -3229,11 +3229,11 @@ expand_byte_code (JCF *jcf, tree method)
 	      int pc = GET_u2 (linenumber_pointer);
 	      linenumber_pointer += 4;
 	      if (pc == PC)
 		{
 		  int line = GET_u2 (linenumber_pointer - 2);
-		  input_location = linemap_line_start (line_table, line, 1);
+		  input_location = linemap_line_start (line_table, line, 1, NULL);
 		  if (input_location > max_location)
 		    max_location = input_location;
 		  if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
 		    break;
 		}
Index: gcc/java/lang.c
===================================================================
--- gcc/java/lang.c	(revision 138935)
+++ gcc/java/lang.c	(working copy)
@@ -602,12 +602,12 @@ java_post_options (const char **pfilenam
 		  free (buf);
 		}
 	    }
 	}
     }
-  linemap_add (line_table, LC_ENTER, false, filename, 0);
-  linemap_add (line_table, LC_RENAME, false, "<built-in>", 0);
+  linemap_add (line_table, LC_ENTER, false, filename, 0, NULL);
+  linemap_add (line_table, LC_RENAME, false, "<built-in>", 0, NULL);
 
   /* Initialize the compiler back end.  */
   return false;
 }
 
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 138935)
+++ gcc/tree.c	(working copy)
@@ -3516,18 +3516,24 @@ expand_location (source_location loc)
   if (loc == 0)
     {
       xloc.file = NULL;
       xloc.line = 0;
       xloc.column = 0;
+#ifdef USE_CARET_DIAGNOSTICS
+      xloc.linebuf = NULL;
+#endif
       xloc.sysp = 0;
     }
   else
     {
       const struct line_map *map = linemap_lookup (line_table, loc);
       xloc.file = map->to_file;
       xloc.line = SOURCE_LINE (map, loc);
       xloc.column = SOURCE_COLUMN (map, loc);
+#ifdef USE_CARET_DIAGNOSTICS
+      xloc.linebuf = SOURCE_LINEBUFFER (map, loc);
+#endif
       xloc.sysp = map->sysp != 0;
     };
   return xloc;
 }
 
Index: gcc/configure
===================================================================
--- gcc/configure	(revision 138935)
+++ gcc/configure	(working copy)
@@ -1011,10 +1011,13 @@ Optional Features:
   --enable-generated-files-in-srcdir
                           put copies of generated files in source dir
                           intended for creating source tarballs for users
                           without texinfo bison or flex.
   --enable-werror-always  enable -Werror despite compiler version
+  --enable-caret-diagnostics
+                          enable printing the source code causing a diagnostic
+			  with a caret symbol indicating the exact location.
   --enable-checking=LIST
 			  enable expensive run-time checks.  With LIST,
 			  enable only specific categories of checks.
 			  Categories are: yes,no,all,none,release.
 			  Flags are: assert,df,fold,gc,gcac,gimple,misc,
@@ -7232,10 +7235,26 @@ warn_cflags=
 if test "x$GCC" = "xyes"; then
   warn_cflags='$(GCC_WARN_CFLAGS)'
 fi
 
 
+# Check whether --enable-caret-diagnostics or --disable-caret-diagnostics was given.
+if test "${enable_caret_diagnostics+set}" = set; then
+  enableval="$enable_caret_diagnostics"
+
+else
+  enable_caret_diagnostics=no
+fi;
+
+if test x$enable_caret_diagnostics = xyes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_CARET_DIAGNOSTICS 1
+_ACEOF
+
+fi
+
 # Enable expensive internal checks
 is_release=
 if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then
   is_release=yes
 fi
@@ -14719,17 +14738,17 @@ echo $ECHO_N "checking the name lister (
 if test "${lt_cv_nm_interface+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:14724: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:14743: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:14727: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:14746: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:14730: output\"" >&5)
+  (eval echo "\"\$as_me:14749: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
   fi
   rm -f conftest*
@@ -15780,11 +15799,11 @@ ia64-*-hpux*)
   fi
   rm -rf conftest*
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 15785 "configure"' > conftest.$ac_ext
+  echo '#line 15804 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; then
@@ -16400,15 +16419,15 @@ else
    # The option is referenced via a variable to avoid confusing sed.
    lt_compile=`echo "$ac_compile" | $SED \
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16405: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16424: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:16409: \$? = $ac_status" >&5
+   echo "$as_me:16428: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
      $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
      $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
@@ -16722,15 +16741,15 @@ else
    # The option is referenced via a variable to avoid confusing sed.
    lt_compile=`echo "$ac_compile" | $SED \
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16727: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16746: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:16731: \$? = $ac_status" >&5
+   echo "$as_me:16750: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
      $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
      $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
@@ -16827,15 +16846,15 @@ else
    # with a dollar sign (not a hyphen), so the echo should work correctly.
    lt_compile=`echo "$ac_compile" | $SED \
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16832: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16851: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:16836: \$? = $ac_status" >&5
+   echo "$as_me:16855: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
      $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
@@ -16882,15 +16901,15 @@ else
    # with a dollar sign (not a hyphen), so the echo should work correctly.
    lt_compile=`echo "$ac_compile" | $SED \
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:16887: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16906: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:16891: \$? = $ac_status" >&5
+   echo "$as_me:16910: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
      $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
@@ -19679,11 +19698,11 @@ else
   lt_cv_dlopen_self=cross
 else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19684 "configure"
+#line 19703 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 #include <dlfcn.h>
 #endif
@@ -19779,11 +19798,11 @@ else
   lt_cv_dlopen_self_static=cross
 else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19784 "configure"
+#line 19803 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 #include <dlfcn.h>
 #endif
Index: gcc/diagnostic.c
===================================================================
--- gcc/diagnostic.c	(revision 138935)
+++ gcc/diagnostic.c	(working copy)
@@ -103,10 +103,13 @@ diagnostic_initialize (diagnostic_contex
   memset (context->diagnostic_count, 0, sizeof context->diagnostic_count);
   context->issue_warnings_are_errors_message = true;
   context->warning_as_error_requested = false;
   memset (context->classify_diagnostic, DK_UNSPECIFIED,
 	  sizeof context->classify_diagnostic);
+#ifdef USE_CARET_DIAGNOSTICS
+  context->show_caret = true;
+#endif
   context->show_option_requested = false;
   context->abort_on_error = false;
   context->internal_error = NULL;
   diagnostic_starter (context) = default_diagnostic_starter;
   diagnostic_finalizer (context) = default_diagnostic_finalizer;
@@ -161,10 +164,47 @@ diagnostic_build_prefix (diagnostic_info
      : flag_show_column && s.column != 0
      ? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text)
      : build_message_string ("%s:%d: %s", s.file, s.line, text));
 }
 
+#ifdef USE_CARET_DIAGNOSTICS
+static const unsigned char *
+get_source_line (expanded_location s)
+{
+  return s.linebuf;
+}
+
+static void
+diagnostic_show_locus (diagnostic_context * context ATTRIBUTE_UNUSED,
+		       diagnostic_info *diagnostic)
+{
+  const unsigned char *line;
+  int max_width = 80;
+  expanded_location s;
+
+  if (!context->show_caret)
+    return;
+
+  s = expand_location (diagnostic->location);
+  line = get_source_line (s);
+  if (line == NULL)
+    return;
+
+  putchar (' ');
+
+  while (max_width > 0 && *line != '\0' && *line != '\n')
+    {
+      max_width--;
+      putchar (*line);
+      line++;
+    }
+  putchar('\n');
+  gcc_assert (s.column > 0);
+  printf (" %*c\n", s.column, '^');
+}
+#endif
+
 /* Take any action which is expected to happen after the diagnostic
    is written out.  This function does not always return.  */
 static void
 diagnostic_action_after_output (diagnostic_context *context,
 				diagnostic_info *diagnostic)
@@ -402,10 +442,13 @@ diagnostic_report_diagnostic (diagnostic
   pp_format (context->printer, &diagnostic->message);
   (*diagnostic_starter (context)) (context, diagnostic);
   pp_output_formatted_text (context->printer);
   (*diagnostic_finalizer (context)) (context, diagnostic);
   pp_flush (context->printer);
+#ifdef USE_CARET_DIAGNOSTICS
+  diagnostic_show_locus (context, diagnostic);
+#endif
   diagnostic_action_after_output (context, diagnostic);
   diagnostic->message.format_spec = saved_format_spec;
   diagnostic->abstract_origin = NULL;
 
   context->lock--;
Index: gcc/diagnostic.h
===================================================================
--- gcc/diagnostic.h	(revision 138935)
+++ gcc/diagnostic.h	(working copy)
@@ -82,10 +82,16 @@ struct diagnostic_context
 
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
   bool show_option_requested;
 
+#ifdef USE_CARET_DIAGNOSTICS
+  /* True if we should print the source line with a caret indicating
+     the location.  */
+  bool show_caret;
+#endif
+
   /* True if we should raise a SIGABRT on errors.  */
   bool abort_on_error;
 
   /* This function is called before any message is printed out.  It is
      responsible for preparing message prefix and such.  For example, it
Index: gcc/input.h
===================================================================
--- gcc/input.h	(revision 138935)
+++ gcc/input.h	(working copy)
@@ -40,10 +40,15 @@ typedef struct GTY (())
   /* The line-location in the source file.  */
   int line;
 
   int column;
 
+#ifdef USE_CARET_DIAGNOSTICS
+  /* The offset location in the source file.  */
+  const unsigned char *linebuf;
+#endif
+
   /* In a system header?. */
   bool sysp;
 } expanded_location;
 
 extern expanded_location expand_location (source_location);
Index: gcc/testsuite/lib/gcc.exp
===================================================================
--- gcc/testsuite/lib/gcc.exp	(revision 138935)
+++ gcc/testsuite/lib/gcc.exp	(working copy)
@@ -148,10 +148,10 @@ proc gcc_target_compile { source dest ty
 	set options [concat "{additional_flags=$TOOL_OPTIONS}" $options]
     }
     if [target_info exists gcc,timeout] {
 	lappend options "timeout=[target_info gcc,timeout]"
     }
-    lappend options "additional_flags=-fno-show-column"
+    lappend options "additional_flags=-fno-show-column -fno-diagnostics-show-caret"
     lappend options "compiler=$GCC_UNDER_TEST"
     set options [dg-additional-files-options $options $source]
     return [target_compile $source $dest $type $options]
 }
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 138935)
+++ gcc/cp/decl.c	(working copy)
@@ -11898,11 +11898,11 @@ finish_function (int flags)
 #endif
 	  /* Hack.  We don't want the middle-end to warn that this
 	     return is unreachable, so put the statement on the
 	     special line 0.  */
 	  {
-	    location_t linezero = linemap_line_start (line_table, 0, 1);
+	    location_t linezero = linemap_line_start (line_table, 0, 1, NULL);
 	    SET_EXPR_LOCATION (stmt, linezero);
 	  }
 	}
 
       if (use_eh_spec_block (current_function_decl))
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h	(revision 138935)
+++ gcc/c-tree.h	(working copy)
@@ -460,11 +460,11 @@ extern void c_init_decl_processing (void
 extern void c_dup_lang_specific_decl (tree);
 extern void c_print_identifier (FILE *, tree, int);
 extern int quals_from_declspecs (const struct c_declspecs *);
 extern struct c_declarator *build_array_declarator (tree, struct c_declspecs *,
 						    bool, bool);
-extern tree build_enumerator (struct c_enum_contents *, tree, tree);
+extern tree build_enumerator (struct c_enum_contents *, tree, tree, location_t);
 extern tree check_for_loop_decls (void);
 extern void mark_forward_parm_decls (void);
 extern void declare_parm_level (void);
 extern void undeclared_variable (tree, location_t);
 extern tree declare_label (tree);
Index: gcc/config.in
===================================================================
--- gcc/config.in	(revision 138935)
+++ gcc/config.in	(working copy)
@@ -375,15 +375,17 @@
 /* Define if your assembler supports thread-local storage. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_TLS
 #endif
 
+
 /* Define if your assembler supports VSX instructions. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_VSX
 #endif
 
+
 /* Define to 1 if you have the `atoll' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_ATOLL
 #endif
 
@@ -1464,10 +1466,17 @@
 #ifndef USED_FOR_TARGET
 #undef USE_AS_TRADITIONAL_FORMAT
 #endif
 
 
+/* Define if diagnostics should print source line with caret symbol indicating
+   exact location. */
+#ifndef USED_FOR_TARGET
+#undef USE_CARET_DIAGNOSTICS
+#endif
+
+
 /* Define to 1 if the 'long long' (or '__int64') is wider than 'long' but
    still efficiently supported by the host hardware. */
 #ifndef USED_FOR_TARGET
 #undef USE_LONG_LONG_FOR_WIDEST_FAST_INT
 #endif
Index: gcc/c-pch.c
===================================================================
--- gcc/c-pch.c	(revision 138935)
+++ gcc/c-pch.c	(working copy)
@@ -427,11 +427,11 @@ c_common_read_pch (cpp_reader *pfile, co
 
   fclose (f);
 
   line_table->trace_includes = saved_trace_includes;
   cpp_set_line_map (pfile, line_table);
-  linemap_add (line_table, LC_RENAME, 0, saved_loc.file, saved_loc.line);
+  linemap_add (line_table, LC_RENAME, 0, saved_loc.file, saved_loc.line, NULL);
 
   /* Give the front end a chance to take action after a PCH file has
      been loaded.  */
   if (lang_post_pch_load)
     (*lang_post_pch_load) ();
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 138935)
+++ gcc/opts.c	(working copy)
@@ -1743,13 +1743,24 @@ common_handle_option (size_t scode, cons
       else
 	return 0;
       break;
 
     case OPT_fdiagnostics_show_option:
-      global_dc->show_option_requested = true;
+      global_dc->show_option_requested = value;
       break;
 
+    case OPT_fdiagnostics_show_caret:
+#ifdef USE_CARET_DIAGNOSTICS
+      global_dc->show_caret = value;
+#else
+      if (value)
+	error ("-fdiagnostics-show-caret is disabled. " 
+	       "Configure GCC with --enable-caret-diagnostics");
+#endif
+      break;
+
+
     case OPT_fdump_:
       if (!dump_switch_p (arg))
 	return 0;
       break;
 
Index: gcc/ada/gcc-interface/trans.c
===================================================================
--- gcc/ada/gcc-interface/trans.c	(revision 138935)
+++ gcc/ada/gcc-interface/trans.c	(working copy)
@@ -272,14 +272,14 @@ gigi (Node_Id gnat_root, int max_gnat_no
       /* We rely on the order isomorphism between files and line maps.  */
       gcc_assert ((int) line_table->used == i);
 
       /* We create the line map for a source file at once, with a fixed number
 	 of columns chosen to avoid jumping over the next power of 2.  */
-      linemap_add (line_table, LC_ENTER, 0, filename, 1);
-      linemap_line_start (line_table, file_info_ptr[i].Num_Source_Lines, 252);
+      linemap_add (line_table, LC_ENTER, 0, filename, 1, NULL);
+      linemap_line_start (line_table, file_info_ptr[i].Num_Source_Lines, 252, NULL);
       linemap_position_for_column (line_table, 252 - 1);
-      linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
+      linemap_add (line_table, LC_LEAVE, 0, NULL, 0, NULL);
     }
 
   /* Initialize ourselves.  */
   init_code_table ();
   init_gnat_to_gnu ();
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 138935)
+++ gcc/c-decl.c	(working copy)
@@ -5931,11 +5931,11 @@ finish_enum (tree enumtype, tree values,
    current enumeration type (one that was begun with start_enum).
    Return a tree-list containing the CONST_DECL and its value.
    Assignment of sequential values by default is handled here.  */
 
 tree
-build_enumerator (struct c_enum_contents *the_enum, tree name, tree value)
+build_enumerator (struct c_enum_contents *the_enum, tree name, tree value, location_t value_loc)
 {
   tree decl, type;
 
   /* Validate and default VALUE.  */
 
@@ -5968,11 +5968,12 @@ build_enumerator (struct c_enum_contents
 	error ("overflow in enumeration values");
     }
 
   if (pedantic && !int_fits_type_p (value, integer_type_node))
     {
-      pedwarn (OPT_pedantic, "ISO C restricts enumerator values to range of %<int%>");
+      pedwarn (OPT_pedantic, "%HISO C restricts enumerator values to range of %<int%>", 
+	       &value_loc);
       /* XXX This causes -pedantic to change the meaning of the program.
 	 Remove?  -zw 2004-03-15  */
       value = convert (integer_type_node, value);
     }
 
Index: gcc/fortran/scanner.c
===================================================================
--- gcc/fortran/scanner.c	(revision 138935)
+++ gcc/fortran/scanner.c	(working copy)
@@ -1509,11 +1509,11 @@ get_file (const char *name, enum lc_reas
 
   f->up = current_file;
   if (current_file != NULL)
     f->inclusion_line = current_file->line;
 
-  linemap_add (line_table, reason, false, f->filename, 1);
+  linemap_add (line_table, reason, false, f->filename, 1, NULL);
 
   return f;
 }
 
 
@@ -1642,11 +1642,11 @@ preprocessor_line (gfc_char_t *c)
 	}
 
       add_file_change (NULL, line);
       current_file = current_file->up;
       linemap_add (line_table, LC_RENAME, false, current_file->filename,
-		   current_file->line);
+		   current_file->line, NULL);
     }
 
   /* The name of the file can be a temporary file produced by
      cpp. Replace the name if it is different.  */
 
@@ -1885,11 +1885,11 @@ load_file (const char *realfilename, con
 
       b = (gfc_linebuf *) gfc_getmem (gfc_linebuf_header_size
 				      + (len + 1) * sizeof (gfc_char_t));
 
       b->location
-	= linemap_line_start (line_table, current_file->line++, 120);
+	= linemap_line_start (line_table, current_file->line++, 120, NULL);
       b->file = current_file;
       b->truncated = trunc;
       wide_strcpy (b->line, line);
 
       if (line_head == NULL)
@@ -1909,11 +1909,11 @@ load_file (const char *realfilename, con
   fclose (input);
 
   if (!initial)
     add_file_change (NULL, current_file->inclusion_line + 1);
   current_file = current_file->up;
-  linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
+  linemap_add (line_table, LC_LEAVE, 0, NULL, 0, NULL);
   return SUCCESS;
 }
 
 
 /* Open a new file and start scanning from that file. Returns SUCCESS
Index: gcc/fortran/f95-lang.c
===================================================================
--- gcc/fortran/f95-lang.c	(revision 138935)
+++ gcc/fortran/f95-lang.c	(working copy)
@@ -250,12 +250,12 @@ gfc_be_parse_file (int set_yydebug ATTRI
 static bool
 gfc_init (void)
 {
   if (!gfc_cpp_enabled ())
     {
-      linemap_add (line_table, LC_ENTER, false, gfc_source_file, 1);
-      linemap_add (line_table, LC_RENAME, false, "<built-in>", 0);
+      linemap_add (line_table, LC_ENTER, false, gfc_source_file, 1, NULL);
+      linemap_add (line_table, LC_RENAME, false, "<built-in>", 0, NULL);
     }
   else
     gfc_cpp_init_0 ();
 
   gfc_init_decl_processing ();
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 138935)
+++ gcc/configure.ac	(working copy)
@@ -340,10 +340,21 @@ warn_cflags=
 if test "x$GCC" = "xyes"; then
   warn_cflags='$(GCC_WARN_CFLAGS)'
 fi
 AC_SUBST(warn_cflags)
 
+AC_ARG_ENABLE(caret-diagnostics,
+[  --enable-caret-diagnostics
+                          enable printing the source code causing a diagnostic
+			  with a caret symbol indicating the exact location.], [],
+[enable_caret_diagnostics=no])
+
+if test x$enable_caret_diagnostics = xyes ; then
+  AC_DEFINE(USE_CARET_DIAGNOSTICS, 1,
+  [Define if diagnostics should print source line with caret symbol indicating exact location.])
+fi
+
 # Enable expensive internal checks
 is_release=
 if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then
   is_release=yes
 fi
Index: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c	(revision 138935)
+++ gcc/c-opts.c	(working copy)
@@ -1446,11 +1446,11 @@ finish_options (void)
     {
       size_t i;
 
       cb_file_change (parse_in,
 		      linemap_add (line_table, LC_RENAME, 0,
-				   _("<built-in>"), 0));
+				   _("<built-in>"), 0, NULL));
 
       cpp_init_builtins (parse_in, flag_hosted);
       c_cpp_builtins (parse_in);
 
       /* We're about to send user input to cpplib, so make it warn for
@@ -1464,11 +1464,11 @@ finish_options (void)
 	 their acceptance on the -std= setting.  */
       cpp_opts->warn_dollars = (cpp_opts->pedantic && !cpp_opts->c99);
 
       cb_file_change (parse_in,
 		      linemap_add (line_table, LC_RENAME, 0,
-				   _("<command-line>"), 0));
+				   _("<command-line>"), 0, NULL));
 
       for (i = 0; i < deferred_count; i++)
 	{
 	  struct deferred_opt *opt = &deferred_opts[i];
 
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 138935)
+++ gcc/common.opt	(working copy)
@@ -445,10 +445,14 @@ Common Joined RejectNegative
 
 fdiagnostics-show-option
 Common
 Amend appropriate diagnostic messages with the command line option that controls them
 
+fdiagnostics-show-caret
+Common
+Show the source line with a caret indicating the column
+
 fdump-
 Common Joined RejectNegative
 -fdump-<type>	Dump various compiler internals to a file
 
 fdump-noaddr
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 138935)
+++ gcc/c-parser.c	(working copy)
@@ -1639,19 +1639,21 @@ c_parser_enum_specifier (c_parser *parse
 	    }
 	  token = c_parser_peek_token (parser);
 	  enum_id = token->value;
 	  /* Set the location in case we create a decl now.  */
 	  c_parser_set_source_position_from_token (token);
+	  comma_loc = c_parser_peek_token (parser)->location;
 	  c_parser_consume_token (parser);
 	  if (c_parser_next_token_is (parser, CPP_EQ))
 	    {
 	      c_parser_consume_token (parser);
+
 	      enum_value = c_parser_expr_no_commas (parser, NULL).value;
 	    }
 	  else
 	    enum_value = NULL_TREE;
-	  enum_decl = build_enumerator (&the_enum, enum_id, enum_value);
+	  enum_decl = build_enumerator (&the_enum, enum_id, enum_value, comma_loc);
 	  TREE_CHAIN (enum_decl) = values;
 	  values = enum_decl;
 	  seen_comma = false;
 	  if (c_parser_next_token_is (parser, CPP_COMMA))
 	    {
Index: libcpp/directives.c
===================================================================
--- libcpp/directives.c	(revision 138935)
+++ libcpp/directives.c	(working copy)
@@ -1011,14 +1011,17 @@ do_linemarker (cpp_reader *pfile)
 void
 _cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
 		     const char *to_file, linenum_type file_line,
 		     unsigned int sysp)
 {
-  const struct line_map *map = linemap_add (pfile->line_table, reason, sysp,
-					    to_file, file_line);
+  const struct line_map *map;
+  const unsigned char *linebuf = (pfile->buffer == NULL) ? NULL : pfile->buffer->next_line;
+
+  map = linemap_add (pfile->line_table, reason, sysp,
+		     to_file, file_line, linebuf);
   if (map != NULL)
-    linemap_line_start (pfile->line_table, map->to_line, 127);
+    linemap_line_start (pfile->line_table, map->to_line, 127, linebuf);
 
   if (pfile->cb.file_change)
     pfile->cb.file_change (pfile, map);
 }
 
Index: libcpp/line-map.c
===================================================================
--- libcpp/line-map.c	(revision 138935)
+++ libcpp/line-map.c	(working copy)
@@ -83,11 +83,12 @@ linemap_free (struct line_maps *set)
    function.  A call to this function can relocate the previous set of
    maps, so any stored line_map pointers should not be used.  */
 
 const struct line_map *
 linemap_add (struct line_maps *set, enum lc_reason reason,
-	     unsigned int sysp, const char *to_file, linenum_type to_line)
+	     unsigned int sysp, const char *to_file, linenum_type to_line, 
+	     const unsigned char ARG_UNUSED (*linebuf))
 {
   struct line_map *map;
   source_location start_location = set->highest_location + 1;
 
   if (set->used && start_location < set->maps[set->used - 1].start_location)
@@ -155,10 +156,12 @@ linemap_add (struct line_maps *set, enum
   map->reason = reason;
   map->sysp = sysp;
   map->start_location = start_location;
   map->to_file = to_file;
   map->to_line = to_line;
+  if (linebuf != NULL)
+    map->linebuf = linebuf;
   set->cache = set->used++;
   map->column_bits = 0;
   set->highest_location = start_location;
   set->highest_line = start_location;
   set->max_column_hint = 0;
@@ -181,11 +184,11 @@ linemap_add (struct line_maps *set, enum
   return map;
 }
 
 source_location
 linemap_line_start (struct line_maps *set, linenum_type to_line,
-		    unsigned int max_column_hint)
+		    unsigned int max_column_hint, const unsigned char *linebuf)
 {
   struct line_map *map = &set->maps[set->used - 1];
   source_location highest = set->highest_location;
   source_location r;
   linenum_type last_line = SOURCE_LINE (map, set->highest_line);
@@ -198,10 +201,11 @@ linemap_line_start (struct line_maps *se
     {
       add_map = true;
     }
   else
     max_column_hint = set->max_column_hint;
+
   if (add_map)
     {
       int column_bits;
       if (max_column_hint > 100000 || highest > 0xC0000000)
 	{
@@ -223,11 +227,11 @@ linemap_line_start (struct line_maps *se
 	 single line we can sometimes just increase its column_bits instead. */
       if (line_delta < 0
 	  || last_line != map->to_line
 	  || SOURCE_COLUMN (map, highest) >= (1U << column_bits))
 	map = (struct line_map *) linemap_add (set, LC_RENAME, map->sysp,
-					       map->to_file, to_line);
+					       map->to_file, to_line, linebuf);
       map->column_bits = column_bits;
       r = map->start_location + ((to_line - map->to_line) << column_bits);
     }
   else
     r = highest - SOURCE_COLUMN (map, highest)
@@ -251,11 +255,12 @@ linemap_position_for_column (struct line
 	  return r;
 	}
       else
 	{
 	  struct line_map *map = &set->maps[set->used - 1];
-	  r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50);
+	  r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50,
+				  SOURCE_LINEBUFFER (map, r));
 	}
     }
   r = r + to_column;
   if (r >= set->highest_location)
     set->highest_location = r;
Index: libcpp/files.c
===================================================================
--- libcpp/files.c	(revision 138935)
+++ libcpp/files.c	(working copy)
@@ -1342,11 +1342,12 @@ _cpp_pop_file_buffer (cpp_reader *pfile,
   /* Invalidate control macros in the #including file.  */
   pfile->mi_valid = false;
 
   if (file->buffer_start)
     {
-      free ((void *) file->buffer_start);
+      /* CARET: We may need to not free this.  */
+      /*      free ((void *) file->buffer_start);*/
       file->buffer_start = NULL;
       file->buffer = NULL;
       file->buffer_valid = false;
     }
 }
Index: libcpp/include/line-map.h
===================================================================
--- libcpp/include/line-map.h	(revision 138935)
+++ libcpp/include/line-map.h	(working copy)
@@ -66,10 +66,12 @@ struct line_map GTY(())
   ENUM_BITFIELD (lc_reason) reason : CHAR_BIT;
   /* The sysp field isn't really needed now that it's in cpp_buffer.  */
   unsigned char sysp;
   /* Number of the low-order source_location bits used for a column number.  */
   unsigned int column_bits : 8;
+  /* The input line.  */
+  const unsigned char * linebuf;
 };
 
 /* A set of chronological line_map structures.  */
 struct line_maps GTY(())
 {
@@ -120,11 +122,11 @@ extern void linemap_check_files_exited (
    most recent linemap_add).   MAX_COLUMN_HINT is the highest column
    number we expect to use in this line (but it does not change
    the highest_location).  */
 
 extern source_location linemap_line_start
-(struct line_maps *set, linenum_type to_line,  unsigned int max_column_hint);
+(struct line_maps *set, linenum_type to_line,  unsigned int max_column_hint, const unsigned char *linebuf);
 
 /* Add a mapping of logical source line to physical source file and
    line number.
 
    The text pointed to by TO_FILE must have a lifetime
@@ -135,11 +137,11 @@ extern source_location linemap_line_star
 
    A call to this function can relocate the previous set of
    maps, so any stored line_map pointers should not be used.  */
 extern const struct line_map *linemap_add
   (struct line_maps *, enum lc_reason, unsigned int sysp,
-   const char *to_file, linenum_type to_line);
+   const char *to_file, linenum_type to_line, const unsigned char *linebuf);
 
 /* Given a logical line, returns the map from which the corresponding
    (source file, line) pair can be deduced.  */
 extern const struct line_map *linemap_lookup
   (struct line_maps *, source_location);
@@ -155,10 +157,30 @@ extern void linemap_print_containing_fil
   ((((LOC) - (MAP)->start_location) >> (MAP)->column_bits) + (MAP)->to_line)
 
 #define SOURCE_COLUMN(MAP, LOC) \
   (((LOC) - (MAP)->start_location) & ((1 << (MAP)->column_bits) - 1))
 
+static inline const unsigned char * 
+SOURCE_LINEBUFFER (const struct line_map * MAP, source_location LOCATION)
+{
+  const unsigned char * linebuf = (MAP)->linebuf;
+  
+  if (linebuf != NULL)
+    {
+      int i = SOURCE_LINE(MAP, LOCATION) - (MAP)->to_line;
+      for (;;) 
+	{
+	  if (i == 0 || *linebuf == '\0')
+	    break;
+	  if (*linebuf == '\n')
+	    i--;
+	  linebuf++;
+	}
+    }
+  return linebuf;
+}
+
 /* Returns the last source line within a map.  This is the (last) line
    of the #include, or other directive, that caused a map change.  */
 #define LAST_SOURCE_LINE(MAP) \
   SOURCE_LINE (MAP, LAST_SOURCE_LINE_LOCATION (MAP))
 #define LAST_SOURCE_LINE_LOCATION(MAP) \
Index: libcpp/internal.h
===================================================================
--- libcpp/internal.h	(revision 138935)
+++ libcpp/internal.h	(working copy)
@@ -67,11 +67,11 @@ struct cset_converter
 
 #define CPP_INCREMENT_LINE(PFILE, COLS_HINT) do { \
     const struct line_maps *line_table = PFILE->line_table; \
     const struct line_map *map = &line_table->maps[line_table->used-1]; \
     linenum_type line = SOURCE_LINE (map, line_table->highest_line); \
-    linemap_line_start (PFILE->line_table, line + 1, COLS_HINT); \
+    linemap_line_start (PFILE->line_table, line + 1, COLS_HINT, PFILE->buffer->cur); \
   } while (0)
 
 /* Maximum nesting of cpp_buffers.  We use a static limit, partly for
    efficiency, and partly to limit runaway recursion.  */
 #define CPP_STACK_MAX 200

^ permalink raw reply	[flat|nested] 66+ messages in thread

end of thread, other threads:[~2012-04-12 17:08 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-06  8:12 [PATCH] Caret diagnostics Manuel López-Ibáñez
2012-04-06 13:42 ` Mike Stump
2012-04-06 14:12   ` Manuel López-Ibáñez
2012-04-06 22:04 ` Jason Merrill
2012-04-06 22:31   ` Manuel López-Ibáñez
2012-04-07  2:31     ` Jason Merrill
2012-04-07 22:29       ` Manuel López-Ibáñez
2012-04-08  4:09         ` Jason Merrill
2012-04-08 12:07           ` Manuel López-Ibáñez
2012-04-08 15:14             ` Gabriel Dos Reis
2012-04-08 16:10               ` Manuel López-Ibáñez
2012-04-08 16:34                 ` Gabriel Dos Reis
2012-04-08 16:14           ` Manuel López-Ibáñez
2012-04-08 16:35             ` Gabriel Dos Reis
2012-04-08 16:53               ` Manuel López-Ibáñez
2012-04-08 17:07                 ` Gabriel Dos Reis
2012-04-09  0:48             ` Jason Merrill
2012-04-09 20:02               ` Manuel López-Ibáñez
2012-04-09 22:28                 ` Jason Merrill
2012-04-10 16:46                   ` Manuel López-Ibáñez
2012-04-10 18:52                     ` Gabriel Dos Reis
2012-04-10 19:38                       ` Manuel López-Ibáñez
2012-04-11  4:04                         ` Gabriel Dos Reis
2012-04-12 16:53                           ` Tom Tromey
2012-04-12 17:08                             ` Gabriel Dos Reis
2012-04-10 22:24                       ` Mike Stump
2012-04-10 23:37                         ` Gabriel Dos Reis
2012-04-11  0:55                           ` Mike Stump
2012-04-11  3:59                             ` Gabriel Dos Reis
2012-04-10 19:32                     ` Jason Merrill
2012-04-10 19:42                       ` Manuel López-Ibáñez
2012-04-10 20:33                         ` Manuel López-Ibáñez
2012-04-11  1:57                           ` Jason Merrill
2012-04-11  4:04                           ` Gabriel Dos Reis
2012-04-11 16:40                           ` H.J. Lu
2012-04-11 18:15                             ` Manuel López-Ibáñez
2012-04-11 18:19                               ` Andrew Pinski
2012-04-11 20:12                               ` Mike Stump
2012-04-11 20:29                             ` Manuel López-Ibáñez
  -- strict thread matches above, loose matches on Subject: below --
2008-08-14 12:12 [PATCH] caret diagnostics (was: broken FE diagnostics wrt complex expressions) Manuel López-Ibáñez
2008-08-14 12:41 ` Joseph S. Myers
2008-08-14 12:57   ` Manuel López-Ibáñez
2008-08-14 13:54     ` Joseph S. Myers
2008-08-14 14:07       ` Manuel López-Ibáñez
2008-08-14 14:41         ` Joseph S. Myers
2008-08-14 15:03           ` Manuel López-Ibáñez
2008-08-14 15:08             ` [PATCH] caret diagnostics Robert Dewar
2008-08-14 15:22               ` Joseph S. Myers
2008-08-14 15:43                 ` Robert Dewar
2008-08-14 15:48               ` Manuel López-Ibáñez
2008-08-14 16:06                 ` Robert Dewar
2008-08-14 16:18                   ` Joseph S. Myers
2008-08-14 17:22                     ` Chris Lattner
2008-08-16 13:30                       ` Paolo Bonzini
2008-08-16 17:19                         ` Joseph S. Myers
2008-08-16 18:59                           ` Paolo Bonzini
2008-08-14 16:18                   ` Manuel López-Ibáñez
2008-08-14 18:49                 ` Mark Mitchell
2008-08-14 19:10                   ` Manuel López-Ibáñez
2008-08-14 19:28                     ` Mark Mitchell
2008-08-14 15:17             ` [PATCH] caret diagnostics (was: broken FE diagnostics wrt complex expressions) Joseph S. Myers
2008-08-14 17:18               ` [PATCH] caret diagnostics Tom Tromey
2008-08-14 17:21                 ` Ralf Wildenhues
2008-08-14 17:34                   ` Joseph S. Myers
2008-08-14 18:20                   ` Tom Tromey
2008-08-14 18:34                     ` Ralf Wildenhues
2008-08-14 19:02                       ` Robert Dewar
2008-08-14 17:33                 ` Joseph S. Myers
2008-08-14 17:51                 ` Joseph S. Myers
2008-08-14 18:52                   ` Mark Mitchell
2008-08-16 10:09                 ` Gabriel Dos Reis
2008-08-16 13:00                   ` Robert Dewar
2008-08-14 15:18             ` [PATCH] caret diagnostics (was: broken FE diagnostics wrt complex expressions) Aldy Hernandez
2008-08-14 15:29               ` Manuel López-Ibáñez
2008-08-14 17:23                 ` Aldy Hernandez
2008-08-16  7:45                   ` Gabriel Dos Reis
2008-08-16 13:12                     ` [PATCH] caret diagnostics Robert Dewar
2008-08-14 18:00 ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).