public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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 ` [PATCH] caret diagnostics Tom Tromey
  0 siblings, 2 replies; 40+ 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] 40+ messages in thread

end of thread, other threads:[~2008-08-16 17:19 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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                   ` Manuel López-Ibáñez
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 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-16  7:44       ` [PATCH] caret diagnostics (was: broken FE diagnostics wrt complex expressions) Gabriel Dos Reis
2008-08-14 18:00 ` [PATCH] caret diagnostics 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).