[CCing Rainer and Mike for the gcc-dg.exp part]

On Thu, 2017-10-26 at 07:33 -0400, Nathan Sidwell wrote:
> On the modules branch, I'm starting to add location
> information.  Line 
> numbers don't really make sense when reporting errors reading a
> binary 
> file, so I wanted to change the diagnostics such that line number
> zero 
> (which is not a line) is not printed -- one just gets the file
> name.  I 
> then noticed that we don't elide column zero (also, not a column
> outside 
> of emacsland).
> 
> This patch changes the diagnostics, such that line-zero prints
> neither 
> line nor column and column-zero doesn't print the column.
> 
> The testsuite presumes that all diagnostics have a column (which may
> or 
> may not be specified in the test pattern).  This patch augments it
> such 
> that a prefix of '-:' indicates 'no column'.  We still default to 
> expecting a column
> 
> The vast bulk is annotating C & C++ tests that do not have a column. 
> Some of those were explicitly checking for column-zero, but many
> just 
> expected some arbitrary column number, which happened to be
> zero.  Of 
> course many (most?) of these diagnostics could be improved to provide
> a 
> column.  Most are from the preprocessor.
> 
> While this is a change in the compiler's output, it's effectively 
> returning to a pre-column formatting for the cases where the column 
> number is not known.  I'd expect (hope?) error message parsers to be 
> robust in that case. (I've found it confusing when column-zero is 
> printed, as I think columns might be zero-based after all.)
> 
> bootstrapped on all languages.
> 
> ok?
> 
> nathan

Indeed, gcc uses 1-based columns, with 0 meaning "the whole line",
whereas Emacs uses 0-based columns (see the comment in line-map.h). 
Probably best to not print them, to avoid confusing the user.

Alternate idea: could show_column become a tri-state:
  * default: show non-zero columns
  * never: never show columns
  * always: always show a column, printing 0 for the no-column case
and then use "always" in our testsuite
?

-fno-show-column would presumably then be a legacy alias for the
"never" value.

> Index: gcc/diagnostic.c
> ===================================================================
> --- gcc/diagnostic.c  (revision 254060)
> +++ gcc/diagnostic.c  (working copy)
> @@ -293,6 +293,24 @@ diagnostic_get_color_for_kind (diagnosti
>    return diagnostic_kind_color[kind];
>  }
>  
> +/* Return a formatted line and column ':%line:%column'.  Elided if
> +   zero.  The result is a statically allocated buffer.  */

> +static const char *
> +maybe_line_and_column (int line, int col)
> +{
> +  static char result[32];
> +
> +  if (line)
> +    {
> +      size_t l = sprintf (result, col ? ":%d:%d" : ":%d", line, col);

Possibly a silly question, but is it OK to have a formatted string
call in which some of the arguments aren't consumed? (here "col" is only
consumed for the true case, which consumes 2 arguments; it's not consumed
for the false case).

> +      gcc_checking_assert (l + 1 < sizeof (result));

Would snprintf be safer?

Please create a selftest for the function, covering these cases:

* line == 0
* line > 0 and col == 0
* line > 0 and col > 0 (checking output for these cases)
* line == INT_MAX and col == INT_MAX (without checking output, just to tickle 
the assert)
* line == INT_MIN and col == INT_MIN (likewise)

Alternatively, please create a selftest for diagnostic_get_location_text,
testing the cases of:
* context->show_column true and false
* N_("<built-in>")
* the above line/col value combos


> +    }
> +  else
> +    result[0] = 0;
> +  return result;
> +}
> +
>  /* Return a malloc'd string describing a location e.g. "foo.c:42:10".
>     The caller is responsible for freeing the memory.  */
>  
> @@ -303,19 +321,13 @@ diagnostic_get_location_text (diagnostic
>    pretty_printer *pp = context->printer;
>    const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
>    const char *locus_ce = colorize_stop (pp_show_color (pp));
> -
> -  if (s.file == NULL)
> -    return build_message_string ("%s%s:%s", locus_cs, progname, locus_ce);
> -
> -  if (!strcmp (s.file, N_("<built-in>")))
> -    return build_message_string ("%s%s:%s", locus_cs, s.file, locus_ce);
> -
> -  if (context->show_column)
> -    return build_message_string ("%s%s:%d:%d:%s", locus_cs, s.file, s.line,
> -                              s.column, locus_ce);
> -  else
> -    return build_message_string ("%s%s:%d:%s", locus_cs, s.file, s.line,
> -                              locus_ce);
> +  const char *file = s.file ? s.file : progname;
> +  int line = strcmp (file, N_("<built-in>")) ? s.line : 0;
> +  int col = context->show_column ? s.column : 0;
> +
> +  const char *line_col = maybe_line_and_column (line, col);
> +  return build_message_string ("%s%s%s:%s", locus_cs, file,
> +                            line_col, locus_ce);
>  }
>  
>  /* Return a malloc'd string describing a location and the severity of the
> @@ -577,21 +589,20 @@ diagnostic_report_current_module (diagno
>        if (! MAIN_FILE_P (map))
>       {
>         map = INCLUDED_FROM (line_table, map);
> -       if (context->show_column)
> -         pp_verbatim (context->printer,
> -                      "In file included from %r%s:%d:%d%R", "locus",
> -                      LINEMAP_FILE (map),
> -                      LAST_SOURCE_LINE (map), LAST_SOURCE_COLUMN (map));
> -       else
> -         pp_verbatim (context->printer,
> -                      "In file included from %r%s:%d%R", "locus",
> -                      LINEMAP_FILE (map), LAST_SOURCE_LINE (map));
> +       const char *line_col
> +         = maybe_line_and_column (LAST_SOURCE_LINE (map),
> +                                  context->show_column
> +                                  ? LAST_SOURCE_COLUMN (map) : 0);
> +       pp_verbatim (context->printer,
> +                    "In file included from %r%s%s%R", "locus",
> +                    LINEMAP_FILE (map), line_col);
>         while (! MAIN_FILE_P (map))
>           {
>             map = INCLUDED_FROM (line_table, map);
> +           line_col = maybe_line_and_column (LAST_SOURCE_LINE (map), 0);
>             pp_verbatim (context->printer,
> -                        ",\n                 from %r%s:%d%R", "locus",
> -                        LINEMAP_FILE (map), LAST_SOURCE_LINE (map));
> +                        ",\n                 from %r%s%s%R", "locus",
> +                        LINEMAP_FILE (map), line_col);
>           }
>         pp_verbatim (context->printer, ":");
>         pp_newline (context->printer);

[...snip lots of additions of "-:" prefixes to dg- directives...]

There are some testcases where we deliberately don't have a *line*
number; what happens to these?

See e.g. gcc.dg/spellcheck-options-*.c

e.g. gcc.dg/spellcheck-options-1.c, which is:

/* { dg-do compile } */
/* { dg-options "-Wcoercion" } */
/* { dg-error "unrecognized command line option '-Wcoercion'; did you mean 
'-Wconversion'?"  "" { target *-*-* } 0 } */



> Index: gcc/testsuite/lib/gcc-dg.exp
> ===================================================================
> --- gcc/testsuite/lib/gcc-dg.exp      (revision 254060)
> +++ gcc/testsuite/lib/gcc-dg.exp      (working copy)
> @@ -1092,24 +1092,27 @@ proc process-message { msgproc msgprefix
>      set newentry [lindex ${dg-messages} end]
>      set expmsg [lindex $newentry 2]
>  
> +    set column ""
>      # Handle column numbers from the specified expression (if there is
>      # one) and set up the search expression that will be used by DejaGnu.
> -    if [regexp "^(\[0-9\]+):" $expmsg "" column] {
> +    if [regexp {^-:} $expmsg] {
> +     # The expected column is -, so shouldn't appear.
> +     set expmsg [string range $expmsg 2 end]
> +    } elseif [regexp {^[0-9]+:} $expmsg column] {
>       # The expression in the directive included a column number.
> -     # Remove "COLUMN:" from the original expression and move it
> +     # Remove it from the original expression and move it
>       # to the proper place in the search expression.
> -     regsub "^\[0-9\]+:" $expmsg "" expmsg
> -     set expmsg "$column: $msgprefix\[^\n\]*$expmsg"
> +     set expmsg [string range $expmsg [string length $column] end]
>      } elseif [string match "" [lindex $newentry 0]] {
>       # The specified line number is 0; don't expect a column number.
> -     set expmsg "$msgprefix\[^\n\]*$expmsg"
>      } else {
>       # There is no column number in the search expression, but we
>       # should expect one in the message itself.
> -     set expmsg "\[0-9\]+: $msgprefix\[^\n\]*$expmsg"
> +     set column {[0-9]+:}
>      }
> -
> +    set expmsg "$column $msgprefix\[^\n\]*$expmsg"
>      set newentry [lreplace $newentry 2 2 $expmsg]
> +
>      set dg-messages [lreplace ${dg-messages} end end $newentry]
>      verbose "process-message:\n${dg-messages}" 2
>  }

My Tcl skills aren't great, so hopefully someone else can review this;
CCing Rainer and Mike.

Also, is the proposed syntax for "no columns" OK?  (note the tristate
idea above)


Hope this is constructive
Dave

Reply via email to