[v4,2/8] libcpp: diagnostics: Support generated data in expanded locations

Message ID 20230809221414.2849878-3-lhyatt@gmail.com
State Accepted
Headers
Series diagnostics: libcpp: Overhaul locations for _Pragma tokens |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Lewis Hyatt Aug. 9, 2023, 10:14 p.m. UTC
  The previous patch in this series introduced the concept of LC_GEN line
maps. This patch continues on the path to using them to improve _Pragma
diagnostics, by adding a new source_id SRC member to struct
expanded_location, which is populated by linemap_expand_location. This
member allows call sites to detect and handle when a location refers to
generated data rather than a plain file name.

The previous FILE member of expanded_location is preserved (although
redundant with SRC), so that call sites which do not and never will care
about generated data do not need to be concerned about it. Call sites that
will care are modified here, to use SRC rather than FILE for comparing
locations.

libcpp/ChangeLog:

	* include/line-map.h (struct expanded_location): Add SRC member. Add
	zero-initializers for all members, since source_id is not a POD
	type.
	(class fixit_hint): Adjust prototype.
	* line-map.cc (linemap_expand_location): Populate the new SRC member
	in the expanded_location.
	(rich_location::maybe_add_fixit): Compare explocs with the new SRC
	field instead of the FILE field.
	(fixit_hint::affects_line_p): Accept a source_id instead of a file
	name, and use it for the comparisons.

gcc/c-family/ChangeLog:

	* c-format.cc (get_corrected_substring): Compare explocs with the
	new SRC field instead of the FILE field.
	* c-indentation.cc (should_warn_for_misleading_indentation): Likewise.
	(assert_get_visual_column_succeeds): Initialize the SRC field in the
	test expanded_location.
	(assert_get_visual_column_fails): Likewise.

gcc/ChangeLog:

	* diagnostic-show-locus.cc (make_range): Adapt to the new
	constructor semantics for struct expanded_location.
	(layout::maybe_add_location_range): Compare explocs with the new SRC
	field instead of the FILE field.
	(layout::validate_fixit_hint_p): Likewise.
	(layout::print_leading_fixits): Use the SRC field in struct
	expanded_location to query fixit_hint::affects_line_p.
	(layout::print_trailing_fixits): Likewise.
	* diagnostic.cc (diagnostic_report_current_module): Use the new SRC
	field in expanded_location to detect LC_GEN locations and identify
	them as such.
	(assert_location_text): Adapt to the new constructor semantics for
	struct expanded_location.
	* input.cc (expand_location_1): Likewise. And when libcpp's
	linemap_expand_location returns a null FILE for generated data,
	replace it with special_fname_generated ().
	(total_lines_num): Handle a generic source_id argument rather than a
	file name only.
	(get_source_text_between): Compare explocs with the new SRC field
	instead of the FILE field.
	(get_substring_ranges_for_loc): Likewise.
	* edit-context.cc (edit_context::apply_fixit): Ignore locations in
	generated data.
	* input.h (LOCATION_SRC): New accessor macro.
---
 gcc/c-family/c-format.cc      |  4 ++--
 gcc/c-family/c-indentation.cc | 10 +++++-----
 gcc/diagnostic-show-locus.cc  | 30 +++++++++++++++++-------------
 gcc/diagnostic.cc             | 19 ++++++++++++-------
 gcc/edit-context.cc           |  2 +-
 gcc/input.cc                  | 21 +++++++++++----------
 gcc/input.h                   |  1 +
 libcpp/include/line-map.h     | 24 ++++++++++++++----------
 libcpp/line-map.cc            | 15 +++++++--------
 9 files changed, 70 insertions(+), 56 deletions(-)
  

Comments

David Malcolm Aug. 11, 2023, 11:02 p.m. UTC | #1
On Wed, 2023-08-09 at 18:14 -0400, Lewis Hyatt wrote:
> The previous patch in this series introduced the concept of LC_GEN line
> maps. This patch continues on the path to using them to improve _Pragma
> diagnostics, by adding a new source_id SRC member to struct
> expanded_location, which is populated by linemap_expand_location. This
> member allows call sites to detect and handle when a location refers to
> generated data rather than a plain file name.
> 
> The previous FILE member of expanded_location is preserved (although
> redundant with SRC), so that call sites which do not and never will care
> about generated data do not need to be concerned about it. Call sites that
> will care are modified here, to use SRC rather than FILE for comparing
> locations.

Thanks; this seems like a good approach.


[...snip...]

> diff --git a/gcc/edit-context.cc b/gcc/edit-context.cc
> index 6f5bc6b9d8f..15052aec417 100644
> --- a/gcc/edit-context.cc
> +++ b/gcc/edit-context.cc
> @@ -295,7 +295,7 @@ edit_context::apply_fixit (const fixit_hint *hint)
>  {
>    expanded_location start = expand_location (hint->get_start_loc ());
>    expanded_location next_loc = expand_location (hint->get_next_loc ());
> -  if (start.file != next_loc.file)
> +  if (start.src != next_loc.src || start.src.is_buffer ())
>      return false;
>    if (start.line != next_loc.line)
>      return false;

Thinking about fix-it hints, it makes sense to reject attempts to
create fix-it hints within generated strings, as we can't apply them or
visualize them.

Does anywhere in the patch kit do that?  Either of 
  rich_location::maybe_add_fixit
or
  rich_location::reject_impossible_fixit
would be good places to do that.


[...snip...]

> diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
> index e59123b18c5..76617fe6129 100644
> --- a/libcpp/include/line-map.h
> +++ b/libcpp/include/line-map.h
> @@ -1410,18 +1410,22 @@ linemap_location_before_p (class line_maps *set,
>  
>  typedef struct
>  {
> -  /* The name of the source file involved.  */
> -  const char *file;
> +  /* The file name of the location involved, or NULL if the location
> +     is not in an external file.  */
> +  const char *file = nullptr;
>  
> -  /* The line-location in the source file.  */
> -  int line;
> -
> -  int column;
> +  /* A source_id recording the file name and/or the in-memory content,
> +     as appropriate.  Users that need to handle in-memory content need
> +     to use this rather than FILE.  */
> +  source_id src;
>  
> -  void *data;
> +  /* The line-location in the source file.  */
> +  int line = 0;
> +  int column = 0;
> +  void *data = nullptr;
>  
> -  /* In a system header?. */
> -  bool sysp;
> +  /* In a system header?  */
> +  bool sysp = false;
>  } expanded_location;

I don't know if we've been using default member initialization yet, but
apparently it's C++11, and thus OK.

[...snip...]


This patch looks good to me, but obviously it has dependencies on the
rest of the kit.

Dave
  
Lewis Hyatt Aug. 14, 2023, 9:41 p.m. UTC | #2
On Fri, Aug 11, 2023 at 07:02:49PM -0400, David Malcolm wrote:
> On Wed, 2023-08-09 at 18:14 -0400, Lewis Hyatt wrote:
> > The previous patch in this series introduced the concept of LC_GEN line
> > maps. This patch continues on the path to using them to improve _Pragma
> > diagnostics, by adding a new source_id SRC member to struct
> > expanded_location, which is populated by linemap_expand_location. This
> > member allows call sites to detect and handle when a location refers to
> > generated data rather than a plain file name.
> > 
> > The previous FILE member of expanded_location is preserved (although
> > redundant with SRC), so that call sites which do not and never will care
> > about generated data do not need to be concerned about it. Call sites that
> > will care are modified here, to use SRC rather than FILE for comparing
> > locations.
> 
> Thanks; this seems like a good approach.
> 
> 
> [...snip...]
> 
> > diff --git a/gcc/edit-context.cc b/gcc/edit-context.cc
> > index 6f5bc6b9d8f..15052aec417 100644
> > --- a/gcc/edit-context.cc
> > +++ b/gcc/edit-context.cc
> > @@ -295,7 +295,7 @@ edit_context::apply_fixit (const fixit_hint *hint)
> >  {
> >    expanded_location start = expand_location (hint->get_start_loc ());
> >    expanded_location next_loc = expand_location (hint->get_next_loc ());
> > -  if (start.file != next_loc.file)
> > +  if (start.src != next_loc.src || start.src.is_buffer ())
> >      return false;
> >    if (start.line != next_loc.line)
> >      return false;
> 
> Thinking about fix-it hints, it makes sense to reject attempts to
> create fix-it hints within generated strings, as we can't apply them or
> visualize them.
> 
> Does anywhere in the patch kit do that?  Either of 
>   rich_location::maybe_add_fixit
> or
>   rich_location::reject_impossible_fixit
> would be good places to do that.
>

So rich_location::reject_impossible_fixit does reject them for _Pragmas now,
because what the frontend sees and passes to it is a virtual location, and it
always rejects virtual locations. But it doesn't reject arbitrary generated
data locations that may be created in an ordinary non-virtual location. I
think it's this one-line change to reject those:

-- >8 --

diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc
index 835e8e1b8cd..382594637ad 100644
--- a/libcpp/line-map.cc
+++ b/libcpp/line-map.cc
@@ -2545,7 +2545,8 @@ rich_location::maybe_add_fixit (location_t start,
     = linemap_client_expand_location_to_spelling_point (next_loc,
                                                        LOCATION_ASPECT_START);
   /* They must be within the same file...  */
-  if (exploc_start.src != exploc_next_loc.src)
+  if (exploc_start.src != exploc_next_loc.src
+      || exploc_start.src.is_buffer ())
     {
       stop_supporting_fixits ();
       return;

-- >8 --

However, there are many selftests in diagnostic-show-locus.cc that actually
verify we generate the fixit hints for generated data, so I would need also to
change those to skip the test in this case as well. That looks like this:

-- >8 --

diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc
index 62c60645e88..884c55e91e9 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostic-show-locus.cc
@@ -3824,6 +3824,8 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
   test_one_liner_simple_caret ();
   test_one_liner_caret_and_range ();
   test_one_liner_multiple_carets_and_ranges ();
+  if (!ltt.m_generated_data)
+    {
       test_one_liner_fixit_insert_before ();
       test_one_liner_fixit_insert_after ();
       test_one_liner_fixit_remove ();
@@ -3835,6 +3837,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
       test_one_liner_many_fixits_2 ();
       test_one_liner_labels ();
     }
+}

 /* Version of all one-liner tests exercising multibyte awareness.  For
    simplicity we stick to using two multibyte characters in the test, U+1F602
@@ -4419,6 +4422,8 @@ test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
   test_one_liner_simple_caret_utf8 ();
   test_one_liner_caret_and_range_utf8 ();
   test_one_liner_multiple_carets_and_ranges_utf8 ();
+  if (!ltt.m_generated_data)
+    {
       test_one_liner_fixit_insert_before_utf8 ();
       test_one_liner_fixit_insert_after_utf8 ();
       test_one_liner_fixit_remove_utf8 ();
@@ -4428,6 +4433,7 @@ test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
       test_one_liner_fixit_validation_adhoc_locations_utf8 ();
       test_one_liner_many_fixits_1_utf8 ();
       test_one_liner_many_fixits_2_utf8 ();
+    }
   test_one_liner_labels_utf8 ();
   test_one_liner_colorized_utf8 ();
 }
@@ -5726,15 +5732,15 @@ diagnostic_show_locus_cc_tests ()
   for_each_line_table_case (test_diagnostic_show_locus_one_liner, true);
   for_each_line_table_case (test_diagnostic_show_locus_one_liner_utf8, true);
   for_each_line_table_case (test_add_location_if_nearby, true);
-  for_each_line_table_case (test_diagnostic_show_locus_fixit_lines, true);
-  for_each_line_table_case (test_fixit_consolidation, true);
-  for_each_line_table_case (test_overlapped_fixit_printing, true);
-  for_each_line_table_case (test_overlapped_fixit_printing_utf8, true);
-  for_each_line_table_case (test_overlapped_fixit_printing_2, true);
-  for_each_line_table_case (test_fixit_insert_containing_newline, true);
-  for_each_line_table_case (test_fixit_insert_containing_newline_2, true);
-  for_each_line_table_case (test_fixit_replace_containing_newline, true);
-  for_each_line_table_case (test_fixit_deletion_affecting_newline, true);
+  for_each_line_table_case (test_diagnostic_show_locus_fixit_lines, false);
+  for_each_line_table_case (test_fixit_consolidation, false);
+  for_each_line_table_case (test_overlapped_fixit_printing, false);
+  for_each_line_table_case (test_overlapped_fixit_printing_utf8, false);
+  for_each_line_table_case (test_overlapped_fixit_printing_2, false);
+  for_each_line_table_case (test_fixit_insert_containing_newline, false);
+  for_each_line_table_case (test_fixit_insert_containing_newline_2, false);
+  for_each_line_table_case (test_fixit_replace_containing_newline, false);
+  for_each_line_table_case (test_fixit_deletion_affecting_newline, false);
   for_each_line_table_case (test_tab_expansion, true);
   for_each_line_table_case (test_escaping_bytes_1, true);
   for_each_line_table_case (test_escaping_bytes_2, true);

-- >8 --

(The above diff was with -w to avoid a lot of useless indent changes, just for
illustration what it does.)

> 
> [...snip...]
> 
> > diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
> > index e59123b18c5..76617fe6129 100644
> > --- a/libcpp/include/line-map.h
> > +++ b/libcpp/include/line-map.h
> > @@ -1410,18 +1410,22 @@ linemap_location_before_p (class line_maps *set,
> >  
> >  typedef struct
> >  {
> > -  /* The name of the source file involved.  */
> > -  const char *file;
> > +  /* The file name of the location involved, or NULL if the location
> > +     is not in an external file.  */
> > +  const char *file = nullptr;
> >  
> > -  /* The line-location in the source file.  */
> > -  int line;
> > -
> > -  int column;
> > +  /* A source_id recording the file name and/or the in-memory content,
> > +     as appropriate.  Users that need to handle in-memory content need
> > +     to use this rather than FILE.  */
> > +  source_id src;
> >  
> > -  void *data;
> > +  /* The line-location in the source file.  */
> > +  int line = 0;
> > +  int column = 0;
> > +  void *data = nullptr;
> >  
> > -  /* In a system header?. */
> > -  bool sysp;
> > +  /* In a system header?  */
> > +  bool sysp = false;
> >  } expanded_location;
> 
> I don't know if we've been using default member initialization yet, but
> apparently it's C++11, and thus OK.
>

Thanks, I feel like it does make things more maintainable. FWIW, I did verify
it builds with gcc 4.8.5.

> [...snip...]
> 
> 
> This patch looks good to me, but obviously it has dependencies on the
> rest of the kit.
> 
> Dave
>

Thank you, please let me know if I should also apply the above tweaks or no?
  

Patch

diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc
index b4eeebcb30e..529b1408179 100644
--- a/gcc/c-family/c-format.cc
+++ b/gcc/c-family/c-format.cc
@@ -4522,9 +4522,9 @@  get_corrected_substring (const substring_loc &fmt_loc,
     = expand_location_to_spelling_point (fmt_substring_range.m_start);
   expanded_location finish
     = expand_location_to_spelling_point (fmt_substring_range.m_finish);
-  if (caret.file != start.file)
+  if (caret.src != start.src)
     return NULL;
-  if (start.file != finish.file)
+  if (start.src != finish.src)
     return NULL;
   if (caret.line != start.line)
     return NULL;
diff --git a/gcc/c-family/c-indentation.cc b/gcc/c-family/c-indentation.cc
index e8d3dece770..fce74991aae 100644
--- a/gcc/c-family/c-indentation.cc
+++ b/gcc/c-family/c-indentation.cc
@@ -334,7 +334,7 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
   const unsigned int tab_width = global_dc->tabstop;
 
   /* They must be in the same file.  */
-  if (next_stmt_exploc.file != body_exploc.file)
+  if (next_stmt_exploc.src != body_exploc.src)
     return false;
 
   /* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider
@@ -363,7 +363,7 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
                                           ^ DON'T WARN HERE.  */
   if (next_stmt_exploc.line == body_exploc.line)
     {
-      if (guard_exploc.file != body_exploc.file)
+      if (guard_exploc.src != body_exploc.src)
 	return true;
       if (guard_exploc.line < body_exploc.line)
 	/* The guard is on a line before a line that contains both
@@ -372,7 +372,7 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
       else if (guard_exploc.line == body_exploc.line)
 	{
 	  /* They're all on the same line.  */
-	  gcc_assert (guard_exploc.file == next_stmt_exploc.file);
+	  gcc_assert (guard_exploc.src == next_stmt_exploc.src);
 	  gcc_assert (guard_exploc.line == next_stmt_exploc.line);
 	  unsigned int guard_vis_column;
 	  unsigned int guard_line_first_nws;
@@ -692,7 +692,7 @@  assert_get_visual_column_succeeds (const location &loc,
 				   unsigned int expected_first_nws)
 {
   expanded_location exploc;
-  exploc.file = file;
+  exploc.src = exploc.file = file;
   exploc.line = line;
   exploc.column = column;
   exploc.data = NULL;
@@ -730,7 +730,7 @@  assert_get_visual_column_fails (const location &loc,
 				const unsigned int tab_width)
 {
   expanded_location exploc;
-  exploc.file = file;
+  exploc.src = exploc.file = file;
   exploc.line = line;
   exploc.column = column;
   exploc.data = NULL;
diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc
index a2aa6b4e0b5..bf969ab6d6a 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostic-show-locus.cc
@@ -697,9 +697,9 @@  static cpp_char_column_policy def_policy ()
 }
 
 /* Create some expanded locations for testing layout_range.  The filename
-   member of the explocs is set to the empty string.  This member will only be
+   member of the explocs is set to NULL.  This member will only be
    inspected by the calls to location_compute_display_column() made from the
-   layout_point constructors.  That function will check for an empty filename
+   layout_point constructors.  That function will check for a NULL filename
    argument and not attempt to open it, rather treating the non-existent data
    as if the display width were the same as the byte count.  Tests exercising a
    real difference between byte count and display width are performed later,
@@ -708,10 +708,14 @@  static cpp_char_column_policy def_policy ()
 static layout_range
 make_range (int start_line, int start_col, int end_line, int end_col)
 {
-  const expanded_location start_exploc
-    = {"", start_line, start_col, NULL, false};
-  const expanded_location finish_exploc
-    = {"", end_line, end_col, NULL, false};
+  expanded_location start_exploc;
+  start_exploc.line = start_line;
+  start_exploc.column = start_col;
+
+  expanded_location finish_exploc;
+  finish_exploc.line = end_line;
+  finish_exploc.column = end_col;
+
   return layout_range (exploc_with_display_col (start_exploc, def_policy (),
 						LOCATION_ASPECT_START),
 		       exploc_with_display_col (finish_exploc, def_policy (),
@@ -1268,12 +1272,12 @@  layout::maybe_add_location_range (const location_range *loc_range,
 
   /* If any part of the range isn't in the same file as the primary
      location of this diagnostic, ignore the range.  */
-  if (start.file != m_exploc.file)
+  if (start.src != m_exploc.src)
     return false;
-  if (finish.file != m_exploc.file)
+  if (finish.src != m_exploc.src)
     return false;
   if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
-    if (caret.file != m_exploc.file)
+    if (caret.src != m_exploc.src)
       return false;
 
   /* Sanitize the caret location for non-primary ranges.  */
@@ -1437,9 +1441,9 @@  layout::get_expanded_location (const line_span *line_span) const
 bool
 layout::validate_fixit_hint_p (const fixit_hint *hint)
 {
-  if (LOCATION_FILE (hint->get_start_loc ()) != m_exploc.file)
+  if (LOCATION_SRC (hint->get_start_loc ()) != m_exploc.src)
     return false;
-  if (LOCATION_FILE (hint->get_next_loc ()) != m_exploc.file)
+  if (LOCATION_SRC (hint->get_next_loc ()) != m_exploc.src)
     return false;
 
   return true;
@@ -2102,7 +2106,7 @@  layout::print_leading_fixits (linenum_type row)
 
       gcc_assert (hint->insertion_p ());
 
-      if (hint->affects_line_p (m_exploc.file, row))
+      if (hint->affects_line_p (m_exploc.src, row))
 	{
 	  /* Printing the '+' with normal colorization
 	     and the inserted line with "insert" colorization
@@ -2554,7 +2558,7 @@  layout::print_trailing_fixits (linenum_type row)
       if (hint->ends_with_newline_p ())
 	continue;
 
-      if (hint->affects_line_p (m_exploc.file, row))
+      if (hint->affects_line_p (m_exploc.src, row))
 	corrections.add_hint (hint);
     }
 
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index c523f215bae..10a377ea209 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -798,13 +798,17 @@  diagnostic_report_current_module (diagnostic_context *context, location_t where)
       if (!includes_seen (context, map))
 	{
 	  bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
-	  expanded_location s = {};
+	  const bool was_gen = ORDINARY_MAP_GENERATED_DATA_P (map);
+	  expanded_location s;
 	  do
 	    {
 	      where = linemap_included_from (map);
 	      map = linemap_included_from_linemap (line_table, map);
 	      bool is_module = MAP_MODULE_P (map);
-	      s.file = LINEMAP_FILE (map);
+	      s.src = ORDINARY_MAP_SOURCE_ID (map);
+	      s.file = (s.src.is_buffer ()
+			? special_fname_generated ()
+			: s.src.get_filename_or_buffer ());
 	      s.line = SOURCE_LINE (map, where);
 	      int col = -1;
 	      if (first && context->show_column)
@@ -823,10 +827,13 @@  diagnostic_report_current_module (diagnostic_context *context, location_t where)
 		 N_("of module"),
 		 N_("In module imported at"),	/* 6 */
 		 N_("imported at"),
+		 N_("In buffer generated from"),   /* 8 */
 		};
 
-	      unsigned index = (was_module ? 6 : is_module ? 4
-				: need_inc ? 2 : 0) + !first;
+	      const unsigned index
+		= was_gen ? 8
+		: ((was_module ? 6 : is_module ? 4 : need_inc ? 2 : 0)
+		   + !first);
 
 	      pp_verbatim (context->printer, "%s%s %r%s%s%R",
 			   first ? "" : was_module ? ", " : ",\n",
@@ -2691,11 +2698,9 @@  assert_location_text (const char *expected_loc_text,
   dc.column_origin = origin;
 
   expanded_location xloc;
-  xloc.file = filename;
+  xloc.src = xloc.file = filename;
   xloc.line = line;
   xloc.column = column;
-  xloc.data = NULL;
-  xloc.sysp = false;
 
   char *actual_loc_text = diagnostic_get_location_text (&dc, xloc);
   ASSERT_STREQ (expected_loc_text, actual_loc_text);
diff --git a/gcc/edit-context.cc b/gcc/edit-context.cc
index 6f5bc6b9d8f..15052aec417 100644
--- a/gcc/edit-context.cc
+++ b/gcc/edit-context.cc
@@ -295,7 +295,7 @@  edit_context::apply_fixit (const fixit_hint *hint)
 {
   expanded_location start = expand_location (hint->get_start_loc ());
   expanded_location next_loc = expand_location (hint->get_next_loc ());
-  if (start.file != next_loc.file)
+  if (start.src != next_loc.src || start.src.is_buffer ())
     return false;
   if (start.line != next_loc.line)
     return false;
diff --git a/gcc/input.cc b/gcc/input.cc
index c1735215b29..c2559614a99 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -236,8 +236,6 @@  expand_location_1 (location_t loc,
       loc = LOCATION_LOCUS (loc);
     }
 
-  memset (&xloc, 0, sizeof (xloc));
-
   if (loc >= RESERVED_LOCATION_COUNT)
     {
       if (!expansion_point_p)
@@ -288,7 +286,12 @@  expand_location_1 (location_t loc,
 
   xloc.data = block;
   if (loc <= BUILTINS_LOCATION)
-    xloc.file = loc == UNKNOWN_LOCATION ? NULL : special_fname_builtin ();
+    {
+      xloc.file = loc == UNKNOWN_LOCATION ? NULL : special_fname_builtin ();
+      xloc.src = xloc.file;
+    }
+  else if (xloc.src.is_buffer ())
+    xloc.file = special_fname_generated ();
 
   return xloc;
 }
@@ -323,11 +326,11 @@  diagnostic_file_cache_fini (void)
    equals the actual number of lines of the file.  */
 
 static size_t
-total_lines_num (const char *file_path)
+total_lines_num (source_id src)
 {
   size_t r = 0;
   location_t l = 0;
-  if (linemap_get_file_highest_location (line_table, file_path, &l))
+  if (linemap_get_file_highest_location (line_table, src, &l))
     {
       gcc_assert (l >= RESERVED_LOCATION_COUNT);
       expanded_location xloc = expand_location (l);
@@ -990,9 +993,7 @@  get_source_text_between (location_t start, location_t end)
 
   /* If the locations are in different files or the end comes before the
      start, give up and return nothing.  */
-  if (!expstart.file || !expend.file)
-    return NULL;
-  if (strcmp (expstart.file, expend.file) != 0)
+  if (!expstart.src || expend.src != expstart.src)
     return NULL;
   if (expstart.line > expend.line)
     return NULL;
@@ -1788,7 +1789,7 @@  get_substring_ranges_for_loc (cpp_reader *pfile,
       expanded_location finish
 	= expand_location_to_spelling_point (src_range.m_finish,
 					     LOCATION_ASPECT_FINISH);
-      if (start.file != finish.file)
+      if (start.src != finish.src)
 	return "range endpoints are in different files";
       if (start.line != finish.line)
 	return "range endpoints are on different lines";
@@ -1839,7 +1840,7 @@  get_substring_ranges_for_loc (cpp_reader *pfile,
 	return "start and finish are spelled in different ordinary maps";
       /* The file from linemap_resolve_location ought to match that from
 	 expand_location_to_spelling_point.  */
-      if (ORDINARY_MAP_SOURCE_ID (start_ord_map) != start.file)
+      if (ORDINARY_MAP_SOURCE_ID (start_ord_map) != start.src)
 	return "mismatching file after resolving linemap";
 
       location_t start_loc
diff --git a/gcc/input.h b/gcc/input.h
index 1b81a995f86..5c578f1a9de 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -175,6 +175,7 @@  extern location_t location_with_discriminator (location_t, int);
 extern bool has_discriminator (location_t);
 extern int get_discriminator_from_loc (location_t);
 
+#define LOCATION_SRC(LOC) ((expand_location (LOC)).src)
 #define LOCATION_FILE(LOC) ((expand_location (LOC)).file)
 #define LOCATION_LINE(LOC) ((expand_location (LOC)).line)
 #define LOCATION_COLUMN(LOC)((expand_location (LOC)).column)
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index e59123b18c5..76617fe6129 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1410,18 +1410,22 @@  linemap_location_before_p (class line_maps *set,
 
 typedef struct
 {
-  /* The name of the source file involved.  */
-  const char *file;
+  /* The file name of the location involved, or NULL if the location
+     is not in an external file.  */
+  const char *file = nullptr;
 
-  /* The line-location in the source file.  */
-  int line;
-
-  int column;
+  /* A source_id recording the file name and/or the in-memory content,
+     as appropriate.  Users that need to handle in-memory content need
+     to use this rather than FILE.  */
+  source_id src;
 
-  void *data;
+  /* The line-location in the source file.  */
+  int line = 0;
+  int column = 0;
+  void *data = nullptr;
 
-  /* In a system header?. */
-  bool sysp;
+  /* In a system header?  */
+  bool sysp = false;
 } expanded_location;
 
 class range_label;
@@ -2065,7 +2069,7 @@  class fixit_hint
 	      const char *new_content);
   ~fixit_hint () { free (m_bytes); }
 
-  bool affects_line_p (const char *file, int line) const;
+  bool affects_line_p (source_id src, int line) const;
   location_t get_start_loc () const { return m_start; }
   location_t get_next_loc () const { return m_next_loc; }
   bool maybe_append (location_t start,
diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc
index e63916054e0..7704c60773b 100644
--- a/libcpp/line-map.cc
+++ b/libcpp/line-map.cc
@@ -1905,8 +1905,6 @@  linemap_expand_location (line_maps *set,
 
 {
   expanded_location xloc;
-
-  memset (&xloc, 0, sizeof (xloc));
   if (IS_ADHOC_LOC (loc))
     {
       xloc.data = get_data_from_adhoc_loc (set, loc);
@@ -1932,8 +1930,9 @@  linemap_expand_location (line_maps *set,
 	abort ();
 
       const line_map_ordinary *ord_map = linemap_check_ordinary (map);
-
-      xloc.file = LINEMAP_FILE (ord_map);
+      xloc.src = ORDINARY_MAP_SOURCE_ID (ord_map);
+      if (!xloc.src.is_buffer ())
+	xloc.file = xloc.src.get_filename_or_buffer ();
       xloc.line = SOURCE_LINE (ord_map, loc);
       xloc.column = SOURCE_COLUMN (ord_map, loc);
       xloc.sysp = LINEMAP_SYSP (ord_map) != 0;
@@ -2534,7 +2533,7 @@  rich_location::maybe_add_fixit (location_t start,
     = linemap_client_expand_location_to_spelling_point (next_loc,
 							LOCATION_ASPECT_START);
   /* They must be within the same file...  */
-  if (exploc_start.file != exploc_next_loc.file)
+  if (exploc_start.src != exploc_next_loc.src)
     {
       stop_supporting_fixits ();
       return;
@@ -2619,19 +2618,19 @@  fixit_hint::fixit_hint (location_t start,
 /* Does this fix-it hint affect the given line?  */
 
 bool
-fixit_hint::affects_line_p (const char *file, int line) const
+fixit_hint::affects_line_p (source_id src, int line) const
 {
   expanded_location exploc_start
     = linemap_client_expand_location_to_spelling_point (m_start,
 							LOCATION_ASPECT_START);
-  if (file != exploc_start.file)
+  if (src != exploc_start.src)
     return false;
   if (line < exploc_start.line)
       return false;
   expanded_location exploc_next_loc
     = linemap_client_expand_location_to_spelling_point (m_next_loc,
 							LOCATION_ASPECT_START);
-  if (file != exploc_next_loc.file)
+  if (src != exploc_next_loc.src)
     return false;
   if (line > exploc_next_loc.line)
       return false;