/* Language-independent diagnostic subroutines for the GNU Compiler
Collection that are only for use in the compilers proper and not
the driver or other programs.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1999-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
#include "tree.h"
#include "diagnostic.h"
+#include "tree-pretty-print.h"
#include "tree-diagnostic.h"
+#include "dumpfile.h" /* TDF_DIAGNOSTIC */
#include "langhooks.h"
#include "langhooks-def.h"
-#include "vec.h"
+#include "intl.h"
/* Prints out, if necessary, the name of the current function
that caused an error. Called from all error and warning functions. */
diagnostic_report_current_function (diagnostic_context *context,
diagnostic_info *diagnostic)
{
- diagnostic_report_current_module (context, diagnostic->location);
- lang_hooks.print_error_function (context, input_filename, diagnostic);
+ diagnostic_report_current_module (context, diagnostic_location (diagnostic));
+ lang_hooks.print_error_function (context, LOCATION_FILE (input_location),
+ diagnostic);
}
-void
+static void
default_tree_diagnostic_starter (diagnostic_context *context,
diagnostic_info *diagnostic)
{
below. */
typedef struct
{
- const struct line_map *map;
+ const line_map_macro *map;
source_location where;
-} loc_t;
+} loc_map_pair;
-DEF_VEC_O (loc_t);
-DEF_VEC_ALLOC_O (loc_t, heap);
/* Unwind the different macro expansions that lead to the token which
location is WHERE and emit diagnostics showing the resulting
Here is the diagnostic that we want the compiler to generate:
- test.c: In function 'g':
- test.c:5:14: error: invalid operands to binary << (have 'double' and 'int')
- test.c:2:9: note: in expansion of macro 'OPERATE'
- test.c:5:3: note: expanded from here
- test.c:5:14: note: in expansion of macro 'SHIFTL'
- test.c:8:3: note: expanded from here
- test.c:8:3: note: in expansion of macro 'MULT2'
- test.c:13:3: note: expanded from here
+ test.c: In function ‘g’:
+ test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
+ test.c:2:9: note: in definition of macro 'OPERATE'
+ test.c:8:3: note: in expansion of macro 'SHIFTL'
+ test.c:13:3: note: in expansion of macro 'MULT'
- The part that goes from the third to the eighth line of this
+ The part that goes from the third to the fifth line of this
diagnostic (the lines containing the 'note:' string) is called the
unwound macro expansion trace. That's the part generated by this
- function.
-
- If FIRST_EXP_POINT_MAP is non-null, *FIRST_EXP_POINT_MAP is set to
- the map of the location in the source that first triggered the
- macro expansion. This must be an ordinary map. */
+ function. */
static void
maybe_unwind_expanded_macro_loc (diagnostic_context *context,
- diagnostic_info *diagnostic,
- source_location where,
- const struct line_map **first_exp_point_map)
+ const diagnostic_info *diagnostic,
+ source_location where)
{
const struct line_map *map;
- VEC(loc_t,heap) *loc_vec = NULL;
+ vec<loc_map_pair> loc_vec = vNULL;
unsigned ix;
- loc_t loc, *iter;
+ loc_map_pair loc, *iter;
map = linemap_lookup (line_table, where);
if (!linemap_macro_expansion_map_p (map))
do
{
loc.where = where;
- loc.map = map;
+ loc.map = linemap_check_macro (map);
- VEC_safe_push (loc_t, heap, loc_vec, &loc);
+ loc_vec.safe_push (loc);
/* WHERE is the location of a token inside the expansion of a
macro. MAP is the map holding the locations of that macro
where = linemap_unwind_toward_expansion (line_table, where, &map);
} while (linemap_macro_expansion_map_p (map));
- if (first_exp_point_map)
- *first_exp_point_map = map;
+ /* Now map is set to the map of the location in the source that
+ first triggered the macro expansion. This must be an ordinary map. */
+ const line_map_ordinary *ord_map = linemap_check_ordinary (map);
/* Walk LOC_VEC and print the macro expansion trace, unless the
first macro which expansion triggered this trace was expanded
inside a system header. */
- if (!LINEMAP_SYSP (map))
- FOR_EACH_VEC_ELT (loc_t, loc_vec, ix, iter)
+ int saved_location_line =
+ expand_location_to_spelling_point (diagnostic_location (diagnostic)).line;
+
+ if (!LINEMAP_SYSP (ord_map))
+ FOR_EACH_VEC_ELT (loc_vec, ix, iter)
{
- source_location resolved_def_loc = 0, resolved_exp_loc = 0;
- diagnostic_t saved_kind;
- const char *saved_prefix;
- source_location saved_location;
+ /* Sometimes, in the unwound macro expansion trace, we want to
+ print a part of the context that shows where, in the
+ definition of the relevant macro, is the token (we are
+ looking at) used. That is the case in the introductory
+ comment of this function, where we print:
+
+ test.c:2:9: note: in definition of macro 'OPERATE'.
+
+ We print that "macro definition context" because the
+ diagnostic line (emitted by the call to
+ pp_ouput_formatted_text in diagnostic_report_diagnostic):
+
+ test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
+
+ does not point into the definition of the macro where the
+ token '<<' (that is an argument to the function-like macro
+ OPERATE) is used. So we must "display" the line of that
+ macro definition context to the user somehow.
+
+ A contrario, when the first interesting diagnostic line
+ points into the definition of the macro, we don't need to
+ display any line for that macro definition in the trace
+ anymore, otherwise it'd be redundant. */
/* Okay, now here is what we want. For each token resulting
from macro expansion we want to show: 1/ where in the
/* Resolve the location iter->where into the locus 1/ of the
comment above. */
- resolved_def_loc =
+ source_location resolved_def_loc =
linemap_resolve_location (line_table, iter->where,
LRK_MACRO_DEFINITION_LOCATION, NULL);
+ /* Don't print trace for locations that are reserved or from
+ within a system header. */
+ const line_map_ordinary *m = NULL;
+ source_location l =
+ linemap_resolve_location (line_table, resolved_def_loc,
+ LRK_SPELLING_LOCATION, &m);
+ if (l < RESERVED_LOCATION_COUNT || LINEMAP_SYSP (m))
+ continue;
+
+ /* We need to print the context of the macro definition only
+ when the locus of the first displayed diagnostic (displayed
+ before this trace) was inside the definition of the
+ macro. */
+ int resolved_def_loc_line = SOURCE_LINE (m, l);
+ if (ix == 0 && saved_location_line != resolved_def_loc_line)
+ {
+ diagnostic_append_note (context, resolved_def_loc,
+ "in definition of macro %qs",
+ linemap_map_get_macro_name (iter->map));
+ /* At this step, as we've printed the context of the macro
+ definition, we don't want to print the context of its
+ expansion, otherwise, it'd be redundant. */
+ continue;
+ }
+
/* Resolve the location of the expansion point of the macro
which expansion gave the token represented by def_loc.
This is the locus 2/ of the earlier comment. */
- resolved_exp_loc =
+ source_location resolved_exp_loc =
linemap_resolve_location (line_table,
MACRO_MAP_EXPANSION_POINT_LOCATION (iter->map),
LRK_MACRO_DEFINITION_LOCATION, NULL);
- saved_kind = diagnostic->kind;
- saved_prefix = context->printer->prefix;
- saved_location = diagnostic->location;
-
- diagnostic->kind = DK_NOTE;
- diagnostic->location = resolved_def_loc;
- pp_base_set_prefix (context->printer,
- diagnostic_build_prefix (context,
- diagnostic));
- pp_newline (context->printer);
- pp_printf (context->printer, "in expansion of macro '%s'",
- linemap_map_get_macro_name (iter->map));
- pp_destroy_prefix (context->printer);
-
- diagnostic->location = resolved_exp_loc;
- pp_base_set_prefix (context->printer,
- diagnostic_build_prefix (context,
- diagnostic));
- pp_newline (context->printer);
- pp_printf (context->printer, "expanded from here");
- pp_destroy_prefix (context->printer);
-
- diagnostic->kind = saved_kind;
- diagnostic->location = saved_location;
- context->printer->prefix = saved_prefix;
+ diagnostic_append_note (context, resolved_exp_loc,
+ "in expansion of macro %qs",
+ linemap_map_get_macro_name (iter->map));
}
- VEC_free (loc_t, heap, loc_vec);
+ loc_vec.release ();
}
/* This is a diagnostic finalizer implementation that is aware of
diagnostic_info *diagnostic)
{
maybe_unwind_expanded_macro_loc (context, diagnostic,
- diagnostic->location,
- NULL);
+ diagnostic_location (diagnostic));
+}
+
+/* Default tree printer. Handles declarations only. */
+static bool
+default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
+ int precision, bool wide, bool set_locus, bool hash)
+{
+ tree t;
+
+ /* FUTURE: %+x should set the locus. */
+ if (precision != 0 || wide || hash)
+ return false;
+
+ switch (*spec)
+ {
+ case 'E':
+ t = va_arg (*text->args_ptr, tree);
+ if (TREE_CODE (t) == IDENTIFIER_NODE)
+ {
+ pp_identifier (pp, IDENTIFIER_POINTER (t));
+ return true;
+ }
+ break;
+
+ case 'D':
+ t = va_arg (*text->args_ptr, tree);
+ if (TREE_CODE (t) == VAR_DECL && DECL_HAS_DEBUG_EXPR_P (t))
+ t = DECL_DEBUG_EXPR (t);
+ break;
+
+ case 'F':
+ case 'T':
+ t = va_arg (*text->args_ptr, tree);
+ break;
+
+ case 'K':
+ percent_K_format (text);
+ return true;
+
+ default:
+ return false;
+ }
+
+ if (set_locus)
+ text->set_location (0, DECL_SOURCE_LOCATION (t));
+
+ if (DECL_P (t))
+ {
+ const char *n = DECL_NAME (t)
+ ? identifier_to_locale (lang_hooks.decl_printable_name (t, 2))
+ : _("<anonymous>");
+ pp_string (pp, n);
+ }
+ else
+ dump_generic_node (pp, t, 0, TDF_DIAGNOSTIC, 0);
+
+ return true;
+}
+
+/* Sets CONTEXT to use language independent diagnostics. */
+void
+tree_diagnostics_defaults (diagnostic_context *context)
+{
+ diagnostic_starter (context) = default_tree_diagnostic_starter;
+ diagnostic_finalizer (context) = default_diagnostic_finalizer;
+ diagnostic_format_decoder (context) = default_tree_printer;
}