diff --git a/gcc/input.c b/gcc/input.c
index dcd348b..8edf05b 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -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>");
diff --git a/gcc/testsuite/g++.dg/warn/Wconversion-real-integer-3.C b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer-3.C
new file mode 100644
index 0000000..a4df010
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer-3.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C
new file mode 100644
index 0000000..29130f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/conversion-real-integer-3.h b/gcc/testsuite/g++.dg/warn/conversion-real-integer-3.h
new file mode 100644
index 0000000..6ed5b2c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/conversion-real-integer-3.h
@@ -0,0 +1,3 @@
+#pragma GCC system_header
+
+#define INT_MAX __INT_MAX__
diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c
index b4b60dc..064fcec 100644
--- a/gcc/tree-diagnostic.c
+++ b/gcc/tree-diagnostic.c
@@ -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.  */
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 4e30742..8496aa1 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -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
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index d7752bb..171aa0f 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -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
