Commit 876217ae by David Malcolm Committed by David Malcolm

PR other/69554: avoid excessive source printing for widely-separated locations

gcc/ChangeLog:
	PR other/69554
	* diagnostic-show-locus.c (struct line_span): New struct.
	(layout::get_first_line): Delete.
	(layout::get_last_line): Delete.
	(layout::get_num_line_spans): New member function.
	(layout::get_line_span): Likewise.
	(layout::print_heading_for_line_span_index_p): Likewise.
	(layout::get_expanded_location): Likewise.
	(layout::calculate_line_spans): Likewise.
	(layout::m_first_line): Delete.
	(layout::m_last_line): Delete.
	(layout::m_line_spans): New field.
	(layout::layout): Update comment.  Replace m_first_line and
	m_last_line with m_line_spans, replacing their initialization
	with a call to calculate_line_spans.
	(diagnostic_show_locus): When printing source lines and
	annotations, rather than looping over a single span
	of lines, instead loop over each line_span within
	the layout, with an inner loop over the lines within them.
	Call the context's start_span callback when changing line spans.
	* diagnostic.c (diagnostic_initialize): Initialize start_span.
	(diagnostic_build_prefix): Break out the building of the location
	part of the string into...
	(diagnostic_get_location_text): ...this new function, rewriting
	it from nested ternary expressions to a sequence of "if"
	statements.
	(default_diagnostic_start_span_fn): New function.
	* diagnostic.h (diagnostic_start_span_fn): New typedef.
	(diagnostic_context::start_span): New field.
	(default_diagnostic_start_span_fn): New prototype.

gcc/fortran/ChangeLog:
	PR other/69554
	* error.c (gfc_diagnostic_start_span): New function.
	(gfc_diagnostics_init): Initialize global_dc's start_span.

gcc/testsuite/ChangeLog:
	PR other/69554
	* gcc.dg/pr69554-1.c: New test.
	* gfortran.dg/pr69554-1.F90: New test.
	* gfortran.dg/pr69554-2.F90: New test.
	* lib/gcc-dg.exp (proc dg-locus): New function.
	* lib/gfortran-dg.exp (proc gfortran-dg-test): Update comment to
	distinguish between the caret-printing and non-caret-printing
	cases.  If caret-printing has been explicitly enabled, bail out
	without attempting to fix up the output.

From-SVN: r233386
parent 8dccd19b
2016-02-12 David Malcolm <dmalcolm@redhat.com> 2016-02-12 David Malcolm <dmalcolm@redhat.com>
PR other/69554
* diagnostic-show-locus.c (struct line_span): New struct.
(layout::get_first_line): Delete.
(layout::get_last_line): Delete.
(layout::get_num_line_spans): New member function.
(layout::get_line_span): Likewise.
(layout::print_heading_for_line_span_index_p): Likewise.
(layout::get_expanded_location): Likewise.
(layout::calculate_line_spans): Likewise.
(layout::m_first_line): Delete.
(layout::m_last_line): Delete.
(layout::m_line_spans): New field.
(layout::layout): Update comment. Replace m_first_line and
m_last_line with m_line_spans, replacing their initialization
with a call to calculate_line_spans.
(diagnostic_show_locus): When printing source lines and
annotations, rather than looping over a single span
of lines, instead loop over each line_span within
the layout, with an inner loop over the lines within them.
Call the context's start_span callback when changing line spans.
* diagnostic.c (diagnostic_initialize): Initialize start_span.
(diagnostic_build_prefix): Break out the building of the location
part of the string into...
(diagnostic_get_location_text): ...this new function, rewriting
it from nested ternary expressions to a sequence of "if"
statements.
(default_diagnostic_start_span_fn): New function.
* diagnostic.h (diagnostic_start_span_fn): New typedef.
(diagnostic_context::start_span): New field.
(default_diagnostic_start_span_fn): New prototype.
2016-02-12 David Malcolm <dmalcolm@redhat.com>
PR driver/69779 PR driver/69779
* gcc.c (driver::finalize): Fix cleanup of "specs". * gcc.c (driver::finalize): Fix cleanup of "specs".
......
...@@ -158,6 +158,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) ...@@ -158,6 +158,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
context->max_errors = 0; context->max_errors = 0;
context->internal_error = NULL; context->internal_error = NULL;
diagnostic_starter (context) = default_diagnostic_starter; diagnostic_starter (context) = default_diagnostic_starter;
context->start_span = default_diagnostic_start_span_fn;
diagnostic_finalizer (context) = default_diagnostic_finalizer; diagnostic_finalizer (context) = default_diagnostic_finalizer;
context->option_enabled = NULL; context->option_enabled = NULL;
context->option_state = NULL; context->option_state = NULL;
...@@ -274,8 +275,34 @@ diagnostic_get_color_for_kind (diagnostic_t kind) ...@@ -274,8 +275,34 @@ diagnostic_get_color_for_kind (diagnostic_t kind)
return diagnostic_kind_color[kind]; return diagnostic_kind_color[kind];
} }
/* Return a malloc'd string describing a location. The caller is /* Return a malloc'd string describing a location e.g. "foo.c:42:10".
responsible for freeing the memory. */ The caller is responsible for freeing the memory. */
static char *
diagnostic_get_location_text (diagnostic_context *context,
expanded_location s)
{
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);
}
/* Return a malloc'd string describing a location and the severity of the
diagnostic, e.g. "foo.c:42:10: error: ". The caller is responsible for
freeing the memory. */
char * char *
diagnostic_build_prefix (diagnostic_context *context, diagnostic_build_prefix (diagnostic_context *context,
const diagnostic_info *diagnostic) const diagnostic_info *diagnostic)
...@@ -290,7 +317,6 @@ diagnostic_build_prefix (diagnostic_context *context, ...@@ -290,7 +317,6 @@ diagnostic_build_prefix (diagnostic_context *context,
const char *text = _(diagnostic_kind_text[diagnostic->kind]); const char *text = _(diagnostic_kind_text[diagnostic->kind]);
const char *text_cs = "", *text_ce = ""; const char *text_cs = "", *text_ce = "";
const char *locus_cs, *locus_ce;
pretty_printer *pp = context->printer; pretty_printer *pp = context->printer;
if (diagnostic_kind_color[diagnostic->kind]) if (diagnostic_kind_color[diagnostic->kind])
...@@ -299,22 +325,14 @@ diagnostic_build_prefix (diagnostic_context *context, ...@@ -299,22 +325,14 @@ diagnostic_build_prefix (diagnostic_context *context,
diagnostic_kind_color[diagnostic->kind]); diagnostic_kind_color[diagnostic->kind]);
text_ce = colorize_stop (pp_show_color (pp)); text_ce = colorize_stop (pp_show_color (pp));
} }
locus_cs = colorize_start (pp_show_color (pp), "locus");
locus_ce = colorize_stop (pp_show_color (pp));
expanded_location s = diagnostic_expand_location (diagnostic); expanded_location s = diagnostic_expand_location (diagnostic);
return char *location_text = diagnostic_get_location_text (context, s);
(s.file == NULL
? build_message_string ("%s%s:%s %s%s%s", locus_cs, progname, locus_ce, char *result = build_message_string ("%s %s%s%s", location_text,
text_cs, text, text_ce) text_cs, text, text_ce);
: !strcmp (s.file, N_("<built-in>")) free (location_text);
? build_message_string ("%s%s:%s %s%s%s", locus_cs, s.file, locus_ce, return result;
text_cs, text, text_ce)
: context->show_column
? build_message_string ("%s%s:%d:%d:%s %s%s%s", locus_cs, s.file, s.line,
s.column, locus_ce, text_cs, text, text_ce)
: build_message_string ("%s%s:%d:%s %s%s%s", locus_cs, s.file, s.line,
locus_ce, text_cs, text, text_ce));
} }
/* Functions at which to stop the backtrace print. It's not /* Functions at which to stop the backtrace print. It's not
...@@ -541,6 +559,16 @@ default_diagnostic_starter (diagnostic_context *context, ...@@ -541,6 +559,16 @@ default_diagnostic_starter (diagnostic_context *context,
} }
void void
default_diagnostic_start_span_fn (diagnostic_context *context,
expanded_location exploc)
{
pp_set_prefix (context->printer,
diagnostic_get_location_text (context, exploc));
pp_string (context->printer, "");
pp_newline (context->printer);
}
void
default_diagnostic_finalizer (diagnostic_context *context, default_diagnostic_finalizer (diagnostic_context *context,
diagnostic_info *diagnostic) diagnostic_info *diagnostic)
{ {
......
...@@ -56,6 +56,10 @@ struct diagnostic_classification_change_t ...@@ -56,6 +56,10 @@ struct diagnostic_classification_change_t
/* Forward declarations. */ /* Forward declarations. */
typedef void (*diagnostic_starter_fn) (diagnostic_context *, typedef void (*diagnostic_starter_fn) (diagnostic_context *,
diagnostic_info *); diagnostic_info *);
typedef void (*diagnostic_start_span_fn) (diagnostic_context *,
expanded_location);
typedef diagnostic_starter_fn diagnostic_finalizer_fn; typedef diagnostic_starter_fn diagnostic_finalizer_fn;
/* This data structure bundles altogether any information relevant to /* This data structure bundles altogether any information relevant to
...@@ -148,6 +152,11 @@ struct diagnostic_context ...@@ -148,6 +152,11 @@ struct diagnostic_context
*/ */
diagnostic_starter_fn begin_diagnostic; diagnostic_starter_fn begin_diagnostic;
/* This function is called by diagnostic_show_locus in between
disjoint spans of source code, so that the context can print
something to indicate that a new span of source code has begun. */
diagnostic_start_span_fn start_span;
/* This function is called after the diagnostic message is printed. */ /* This function is called after the diagnostic message is printed. */
diagnostic_finalizer_fn end_diagnostic; diagnostic_finalizer_fn end_diagnostic;
...@@ -296,6 +305,8 @@ extern void diagnostic_append_note (diagnostic_context *, location_t, ...@@ -296,6 +305,8 @@ extern void diagnostic_append_note (diagnostic_context *, location_t,
#endif #endif
extern char *diagnostic_build_prefix (diagnostic_context *, const diagnostic_info *); extern char *diagnostic_build_prefix (diagnostic_context *, const diagnostic_info *);
void default_diagnostic_starter (diagnostic_context *, diagnostic_info *); void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
void default_diagnostic_start_span_fn (diagnostic_context *,
expanded_location);
void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *); void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
void diagnostic_set_caret_max_width (diagnostic_context *context, int value); void diagnostic_set_caret_max_width (diagnostic_context *context, int value);
void diagnostic_action_after_output (diagnostic_context *, diagnostic_t); void diagnostic_action_after_output (diagnostic_context *, diagnostic_t);
......
2016-02-12 David Malcolm <dmalcolm@redhat.com>
PR other/69554
* error.c (gfc_diagnostic_start_span): New function.
(gfc_diagnostics_init): Initialize global_dc's start_span.
2016-02-11 Andre Vehreschild <vehre@gcc.gnu.org> 2016-02-11 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/69296 PR fortran/69296
......
...@@ -1103,6 +1103,20 @@ gfc_diagnostic_starter (diagnostic_context *context, ...@@ -1103,6 +1103,20 @@ gfc_diagnostic_starter (diagnostic_context *context,
} }
static void static void
gfc_diagnostic_start_span (diagnostic_context *context,
expanded_location exploc)
{
char *locus_prefix;
locus_prefix = gfc_diagnostic_build_locus_prefix (context, exploc);
pp_verbatim (context->printer, locus_prefix);
free (locus_prefix);
pp_newline (context->printer);
/* Fortran uses an empty line between locus and caret line. */
pp_newline (context->printer);
}
static void
gfc_diagnostic_finalizer (diagnostic_context *context, gfc_diagnostic_finalizer (diagnostic_context *context,
diagnostic_info *diagnostic ATTRIBUTE_UNUSED) diagnostic_info *diagnostic ATTRIBUTE_UNUSED)
{ {
...@@ -1426,6 +1440,7 @@ void ...@@ -1426,6 +1440,7 @@ void
gfc_diagnostics_init (void) gfc_diagnostics_init (void)
{ {
diagnostic_starter (global_dc) = gfc_diagnostic_starter; diagnostic_starter (global_dc) = gfc_diagnostic_starter;
global_dc->start_span = gfc_diagnostic_start_span;
diagnostic_finalizer (global_dc) = gfc_diagnostic_finalizer; diagnostic_finalizer (global_dc) = gfc_diagnostic_finalizer;
diagnostic_format_decoder (global_dc) = gfc_format_decoder; diagnostic_format_decoder (global_dc) = gfc_format_decoder;
global_dc->caret_chars[0] = '1'; global_dc->caret_chars[0] = '1';
......
2016-02-12 David Malcolm <dmalcolm@redhat.com> 2016-02-12 David Malcolm <dmalcolm@redhat.com>
PR other/69554
* gcc.dg/pr69554-1.c: New test.
* gfortran.dg/pr69554-1.F90: New test.
* gfortran.dg/pr69554-2.F90: New test.
* lib/gcc-dg.exp (proc dg-locus): New function.
* lib/gfortran-dg.exp (proc gfortran-dg-test): Update comment to
distinguish between the caret-printing and non-caret-printing
cases. If caret-printing has been explicitly enabled, bail out
without attempting to fix up the output.
2016-02-12 David Malcolm <dmalcolm@redhat.com>
PR driver/69265 PR driver/69265
PR driver/69453 PR driver/69453
* gcc.dg/spellcheck-options-3.c: New test case. * gcc.dg/spellcheck-options-3.c: New test case.
......
/* { dg-options "-fdiagnostics-show-caret" } */
/* Various versions of the same C error, with a variety of line spacing,
and of columns, to exercise the line-span handling in
diagnostic-show-locus.c (PR other/69554). */
/* All on one line. */
int test_1 (const char *p, const char *q)
{
return (p + 1) + (q + 1); /* { dg-error "invalid operands" } */
/* { dg-begin-multiline-output "" }
return (p + 1) + (q + 1);
~~~~~~~ ^ ~~~~~~~
{ dg-end-multiline-output "" } */
}
/* On separate lines, but without intervening lines.
This can be printed as a single span of lines. */
int test_2 (const char *p, const char *q)
{
return (p + 1)
+ /* { dg-error "invalid operands" } */
(q + 1);
/* { dg-begin-multiline-output "" }
return (p + 1)
~~~~~~~
+
^
(q + 1);
~~~~~~~
{ dg-end-multiline-output "" } */
}
/* On separate lines, with an intervening line between lines 1 and 2.
This is printed as 2 "spans" of lines, broken up by the intervening
line. */
int test_3 (const char *p, const char *q)
{
return (p + 1) /* { dg-locus "10" } */
+ /* { dg-error "invalid operands" } */
(q + 1);
/* { dg-locus "12" "" { target *-*-* } "44" } */
/* { dg-begin-multiline-output "" }
return (p + 1)
~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
+
^
(q + 1);
~~~~~~~
{ dg-end-multiline-output "" } */
}
/* As above, but the intervening line is between lines 2 and 3,
so that the 2 spans are grouped the other way. */
int test_4 (const char *p, const char *q)
{
return (p + 1)
+ /* { dg-error "invalid operands" } */
(q + 1); /* { dg-locus "14" } */
/* { dg-begin-multiline-output "" }
return (p + 1)
~~~~~~~
+
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
(q + 1);
~~~~~~~
{ dg-end-multiline-output "" } */
}
/* On separate lines, with intervening lines.
This is printed as 3 "spans" of lines, each span being an
individual line. */
int test_5 (const char *p, const char *q)
{
return (p + 1) /* { dg-locus "10" } */
+ /* { dg-error "invalid operands" } */
(q + 1); /* { dg-locus "14" } */
/* { dg-locus "12" "" { target *-*-* } "88" } */
/* { dg-begin-multiline-output "" }
return (p + 1)
~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
+
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
(q + 1);
~~~~~~~
{ dg-end-multiline-output "" } */
}
/* On separate lines, with numerous intervening lines.
This is printed as 3 "spans" of lines, each span being an
individual line. */
int test_6 (const char *p, const char *q)
{
return (p + 1) /* { dg-locus "10" } */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas nisl sapien, rutrum non euismod et, rutrum ac felis.
Morbi nec nisi ipsum. Quisque pulvinar ante nec urna rhoncus,
a cursus nisi commodo. Praesent euismod neque lectus, at
dapibus ipsum gravida in. Pellentesque tempor massa eu viverra
feugiat. Proin eleifend pulvinar urna, ut dapibus metus vehicula
ac. Suspendisse rutrum finibus quam, ac dignissim diam blandit
maximus. In blandit viverra pulvinar. Praesent vel tellus
elementum, placerat lacus quis, ornare lectus. Donec ac
eleifend nulla, sit amet condimentum risus. Vestibulum aliquam
maximus ante non pellentesque. Praesent mollis ante in risus
feugiat hendrerit. Praesent feugiat maximus urna nec blandit. */
+ /* { dg-error "invalid operands" } */
/* Vestibulum ac nunc eget enim tempor tristique. Suspendisse
potenti. Nam et sollicitudin enim. Morbi sed tincidunt lectus.
Sed facilisis velit at ante maximus feugiat. Sed vestibulum mi
id leo tempor, sed ullamcorper sapien efficitur. Vestibulum purus
lacus, dignissim non magna at, tincidunt luctus nisl. Cum sociis
natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Donec elit elit, laoreet a dolor quis, eleifend
dapibus metus. Proin lectus turpis, eleifend nec pharetra eu,
fermentum in lacus. Morbi sit amet mauris orci. Nam sagittis,
nibh vel fermentum dictum, purus ex hendrerit odio, feugiat
fringilla sapien elit vitae nisl. Fusce mattis commodo risus
nec convallis. */
(q + 1); /* { dg-locus "14" } */
/* { dg-locus "12" "" { target *-*-* } "125" } */
/* { dg-begin-multiline-output "" }
return (p + 1)
~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
+
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
(q + 1);
~~~~~~~
{ dg-end-multiline-output "" } */
}
! { dg-do compile }
! { dg-options "-fdiagnostics-show-caret" }
! { dg-allow-blank-lines-in-output 1 }
program main
goto 1000
1000 continue ! first instance
a = a
a = a
a = a
1000 continue ! second instance
end
#if 0
! { dg-locus "4" "" { target *-*-* } "7" }
! { dg-begin-multiline-output "" }
1000 continue ! first instance
1
! { dg-end-multiline-output "" }
! { dg-locus "4" "" { target *-*-* } "11" }
! { dg-begin-multiline-output "" }
1000 continue ! second instance
2
Error: Duplicate statement label 1000 at (1) and (2)
! { dg-end-multiline-output "" }
#endif
! { dg-do compile }
! { dg-options "-fdiagnostics-show-caret" }
! { dg-allow-blank-lines-in-output 1 }
program main
goto 1000
1000 continue ! first instance
1000 continue ! second instance
end
#if 0
! { dg-locus "4" "" { target *-*-* } "7" }
! { dg-begin-multiline-output "" }
1000 continue ! first instance
1
1000 continue ! second instance
2
Error: Duplicate statement label 1000 at (1) and (2)
! { dg-end-multiline-output "" }
#endif
...@@ -988,6 +988,33 @@ proc dg-message { args } { ...@@ -988,6 +988,33 @@ proc dg-message { args } {
process-message saved-dg-warning "" $args process-message saved-dg-warning "" $args
} }
# Look for a location marker of the form
# file:line:column:
# with no extra text (e.g. a line-span separator).
proc dg-locus { args } {
upvar dg-messages dg-messages
# Process the dg- directive, including adding the regular expression
# to the new message entry in dg-messages.
set msgcnt [llength ${dg-messages}]
eval saved-dg-warning $args
# If the target expression wasn't satisfied there is no new message.
if { [llength ${dg-messages}] == $msgcnt } {
return;
}
# Get the entry for the new message. Prepend the message prefix to
# the regular expression and make it match a single line.
set newentry [lindex ${dg-messages} end]
set expmsg [lindex $newentry 2]
set newentry [lreplace $newentry 2 2 $expmsg]
set dg-messages [lreplace ${dg-messages} end end $newentry]
verbose "process-message:\n${dg-messages}" 2
}
# Check the existence of a gdb in the path, and return true if there # Check the existence of a gdb in the path, and return true if there
# is one. # is one.
# #
......
...@@ -26,7 +26,15 @@ proc gfortran-dg-test { prog do_what extra_tool_flags } { ...@@ -26,7 +26,15 @@ proc gfortran-dg-test { prog do_what extra_tool_flags } {
set comp_output [lindex $result 0] set comp_output [lindex $result 0]
set output_file [lindex $result 1] set output_file [lindex $result 1]
# gfortran error messages look like this: # gcc's default is to print the caret and source code, but
# most test cases implicitly use the flag -fno-diagnostics-show-caret
# to disable caret (and source code) printing.
#
# However, a few test cases override this back to the default by
# explicily supplying "-fdiagnostics-show-caret", so that we can have
# test coverage for caret/source code printing.
#
# gfortran error messages with caret-printing look like this:
# [name]:[locus]: # [name]:[locus]:
# #
# some code # some code
...@@ -49,7 +57,14 @@ proc gfortran-dg-test { prog do_what extra_tool_flags } { ...@@ -49,7 +57,14 @@ proc gfortran-dg-test { prog do_what extra_tool_flags } {
# 1 2 # 1 2
# Error: Some error at (1) and (2) # Error: Some error at (1) and (2)
# #
# or # If this is such a test case, skip the rest of this function, so
# that the test case can explicitly verify the output that it expects.
if {[string first "-fdiagnostics-show-caret" $extra_tool_flags] >= 0} {
return [list $comp_output $output_file]
}
# Otherwise, caret-printing is disabled.
# gfortran errors with caret-printing disabled look like this:
# [name]:[locus]: Error: Some error # [name]:[locus]: Error: Some error
# or # or
# [name]:[locus]: Error: (1) # [name]:[locus]: Error: (1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment