@@ -35,7 +35,14 @@ struct line_maps *line_table;
location is set to the string "<built-in>". If EXPANSION_POINT_P is
TRUE and LOC is virtual, then it is resolved to the expansion
point of the involved macro. Otherwise, it is resolved to the
- spelling location of the token. */
+ spelling location of the token.
+
+ When resolving to the spelling location of the token, if the
+ resulting location is for a built-in location (that is, it has no
+ associated line/column) in the context of a macro expansion, the
+ returned location is the first one (while unwinding the macro
+ location towards its expansion point) that is in real source
+ code. */
static expanded_location
expand_location_1 (source_location loc,
@@ -43,12 +50,29 @@ expand_location_1 (source_location loc,
{
expanded_location xloc;
const struct line_map *map;
-
- loc = linemap_resolve_location (line_table, loc,
- expansion_point_p
- ? LRK_MACRO_EXPANSION_POINT
- : LRK_SPELLING_LOCATION, &map);
- xloc = linemap_expand_location (line_table, map, loc);
+ enum location_resolution_kind lrk = LRK_MACRO_EXPANSION_POINT;
+
+ memset (&xloc, 0, sizeof (xloc));
+
+ if (loc >= RESERVED_LOCATION_COUNT)
+ {
+ if (!expansion_point_p)
+ {
+ /* We want to resolve LOC to its spelling location.
+
+ But if that spelling location is a reserved location that
+ appears in the context of a macro expansion (like for a
+ location for a built-in token), let's consider the first
+ location (toward the expansion point) that is not reserved;
+ that is, the first location that is in real source code. */
+ loc = linemap_unwind_to_first_non_reserved_loc (line_table,
+ loc, &map);
+ lrk = LRK_SPELLING_LOCATION;
+ }
+ loc = linemap_resolve_location (line_table, loc,
+ lrk, &map);
+ xloc = linemap_expand_location (line_table, map, loc);
+ }
if (loc <= BUILTINS_LOCATION)
xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
new file mode 100644
@@ -0,0 +1,20 @@
+// { dg-do compile }
+// { dg-options "-Wconversion -ftrack-macro-expansion=2" }
+// { dg-require-effective-target int32plus }
+
+#include "conversion-real-integer-3.h"
+
+float vfloat;
+
+void h (void)
+{
+ // We want to trigger an error on the token INT_MAX below, that is
+ // a macro that expands to the built-in __INT_MAX__. Furthermore,
+ // INT_MAX is defined inside a system header.
+ //
+ // The behaviour we want is that the diagnostic should point to
+ // the locus that inside the source code here, at the relevant
+ // line below, even with -ftrack-macro-expansion. We don't want
+ // it to point to the any locus that is inside the system header.
+ vfloat = INT_MAX; // { dg-warning "conversion to .float. alters .int. constant value" }
+}
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile }
+/* { dg-options "-Wconversion -ftrack-macro-expansion=2" } */
+/* { dg-require-effective-target int32plus } */
+
+// Before the fix that came with this test, we'd output an error for
+// the __INT_MAX__ token. That token has a BUILTINS_LOCATION
+// location, so the the location prefix in the warning message would
+// be:
+// <built-in>:0:0: warning: conversion to 'float' alters 'int' constant value
+//
+// Note the useless and confusing <built-in>:0:0 prefix. This is
+// because '__INT_MAX__' being an internal macro token, it has a
+// BUILTINS_LOCATION location.
+//
+// In this case, we want the error message to refer to the first
+// location (in the macro expansion context) that is not a location
+// for a built-in token. That location would be the one for where (in
+// real source code) the __INT_MAX__ macro has been expanded.
+//
+// That would be something like:
+//
+// gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C:21:17: warning: conversion to 'float' alters 'int' constant value
+//
+// That is more useful.
+
+#define INT_MAX __INT_MAX__ // { dg-warning "conversion to .float. alters .int. constant value" }
+
+float vfloat;
+
+void h (void)
+{
+ vfloat = INT_MAX; // { dg-message "expanded from here" }
+}
new file mode 100644
@@ -0,0 +1,3 @@
+#pragma GCC system_header
+
+#define INT_MAX __INT_MAX__
@@ -168,6 +168,18 @@ maybe_unwind_expanded_macro_loc (diagnostic_context *context,
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 struct line_map *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;
+ }
+
/* 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. */
@@ -666,12 +666,30 @@ source_location linemap_resolve_location (struct line_maps *,
location L of the point where M got expanded. If L is a spelling
location inside a macro expansion M', then this function returns
the point where M' was expanded. LOC_MAP is an output parameter.
- When non-NULL, *LOC_MAP is set the the map of the returned
+ When non-NULL, *LOC_MAP is set to the map of the returned
location. */
source_location linemap_unwind_toward_expansion (struct line_maps *,
source_location loc,
const struct line_map **loc_map);
+/* If LOC is the virtual location of a token coming from the expansion
+ of a macro M and if its spelling location is reserved (e.g, a
+ location for a built-in token), then this function unwinds (using
+ linemap_unwind_toward_expansion) the location until a location that
+ is not reserved and is not in a system header is reached. In other
+ words, this unwinds the reserved location until a location that is
+ in real source code is reached.
+
+ Otherwise, if the spelling location for LOC is not reserved or if
+ LOC doesn't come from the expansion of a macro, the function
+ returns LOC as is and *MAP is not touched.
+
+ *MAP is set to the map of the returned location if the later is
+ different from LOC. */
+source_location linemap_unwind_to_first_non_reserved_loc (struct line_maps *,
+ source_location loc,
+ const struct line_map **map);
+
/* Expand source code location LOC and return a user readable source
code location. LOC must be a spelling (non-virtual) location. If
it's a location < RESERVED_LOCATION_COUNT a zeroed expanded source
@@ -1111,6 +1111,55 @@ linemap_unwind_toward_expansion (struct line_maps *set,
return resolved_location;
}
+/* If LOC is the virtual location of a token coming from the expansion
+ of a macro M and if its spelling location is reserved (e.g, a
+ location for a built-in token), then this function unwinds (using
+ linemap_unwind_toward_expansion) the location until a location that
+ is not reserved and is not in a sytem header is reached. In other
+ words, this unwinds the reserved location until a location that is
+ in real source code is reached.
+
+ Otherwise, if the spelling location for LOC is not reserved or if
+ LOC doesn't come from the expansion of a macro, the function
+ returns LOC as is and *MAP is not touched.
+
+ *MAP is set to the map of the returned location if the later is
+ different from LOC. */
+source_location
+linemap_unwind_to_first_non_reserved_loc (struct line_maps *set,
+ source_location loc,
+ const struct line_map **map)
+{
+ source_location resolved_loc;
+ const struct line_map *map0 = NULL, *map1 = NULL;
+
+ map0 = linemap_lookup (set, loc);
+ if (!linemap_macro_expansion_map_p (map0))
+ return loc;
+
+ resolved_loc = linemap_resolve_location (set, loc,
+ LRK_SPELLING_LOCATION,
+ &map1);
+
+ if (resolved_loc >= RESERVED_LOCATION_COUNT
+ && !LINEMAP_SYSP (map1))
+ return loc;
+
+ while (linemap_macro_expansion_map_p (map0)
+ && (resolved_loc < RESERVED_LOCATION_COUNT
+ || LINEMAP_SYSP (map1)))
+ {
+ loc = linemap_unwind_toward_expansion (set, loc, &map0);
+ resolved_loc = linemap_resolve_location (set, loc,
+ LRK_SPELLING_LOCATION,
+ &map1);
+ }
+
+ if (map != NULL)
+ *map = map0;
+ return loc;
+}
+
/* Expand source code location LOC and return a user readable source
code location. LOC must be a spelling (non-virtual) location. If
it's a location < RESERVED_LOCATION_COUNT a zeroed expanded source