diff --git c/libcpp/include/cpplib.h w/libcpp/include/cpplib.h
index 8e398863cf6..81be6457951 100644
--- c/libcpp/include/cpplib.h
+++ w/libcpp/include/cpplib.h
@@ -971,6 +1002,9 @@ extern cpp_callbacks *cpp_get_callbacks (cpp_reader *) ATTRIBUTE_PURE;
 extern void cpp_set_callbacks (cpp_reader *, cpp_callbacks *);
 extern class mkdeps *cpp_get_deps (cpp_reader *) ATTRIBUTE_PURE;
 
+extern const char *cpp_find_header_unit (cpp_reader *, const char *file,
+					 bool angle_p,  location_t);
+
 /* This function reads the file, but does not start preprocessing.  It
    returns the name of the original file; this is the same as the
    input file, except for preprocessed input.  This will generate at
diff --git c/libcpp/files.c w/libcpp/files.c
index 5af41364d0a..c23cd18ef2a 100644
--- c/libcpp/files.c
+++ w/libcpp/files.c
@@ -111,6 +111,9 @@ struct _cpp_file
 
   /* If this file is implicitly preincluded.  */
   bool implicit_preinclude : 1;
+
+  /* Is a C++ Module header unit.  */
+  int header_unit : 2;
 };
 
 /* A singly-linked list for all searches for a given file name, with
@@ -891,9 +894,9 @@ has_unique_contents (cpp_reader *pfile, _cpp_file *file, bool import,
 }
 
 /* Place the file referenced by FILE into a new buffer on the buffer
-   stack if possible.  IMPORT is true if this stacking attempt is
-   because of a #import directive.  Returns true if a buffer is
-   stacked.  Use LOC for any diagnostics.  */
+   stack if possible.  Returns true if a buffer is stacked.  Use LOC
+   for any diagnostics.  */
+
 bool
 _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
 		 location_t loc)
@@ -901,39 +904,75 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
   if (is_known_idempotent_file (pfile, file, type == IT_IMPORT))
     return false;
 
-  if (!read_file (pfile, file, loc))
-    return false;
-
-  if (!has_unique_contents (pfile, file, type == IT_IMPORT, loc))
-    return false;
-
   int sysp = 0;
-  if (pfile->buffer && file->dir)
-    sysp = MAX (pfile->buffer->sysp, file->dir->sysp);
-
-  /* Add the file to the dependencies on its first inclusion.  */
-  if (CPP_OPTION (pfile, deps.style) > (sysp != 0)
-      && !file->stack_count
-      && file->path[0]
-      && !(file->main_file && CPP_OPTION (pfile, deps.ignore_main_file)))
-    deps_add_dep (pfile->deps, file->path);
-
-  /* Clear buffer_valid since _cpp_clean_line messes it up.  */
-  file->buffer_valid = false;
-  file->stack_count++;
-
-  /* Stack the buffer.  */
-  cpp_buffer *buffer
-    = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
-		       CPP_OPTION (pfile, preprocessed)
-		       && !CPP_OPTION (pfile, directives_only));
-  buffer->file = file;
-  buffer->sysp = sysp;
-  buffer->to_free = file->buffer_start;
+  char *buf = nullptr;
 
-  /* Initialize controlling macro state.  */
-  pfile->mi_valid = true;
-  pfile->mi_cmacro = 0;
+  /* Check C++ module include translation.  */
+  if (!file->header_unit && type < IT_HEADER_HWM
+      /* Do not include translate include-next.  */
+      && type != IT_INCLUDE_NEXT
+      && pfile->cb.translate_include)
+    buf = (pfile->cb.translate_include
+	   (pfile, pfile->line_table, loc, file->path));
+
+  if (buf)
+    {
+      /* We don't increment the line number at the end of a buffer,
+	 because we don't usually need that location (we're popping an
+	 include file).  However in this case we do want to do the
+	 increment.  So push a writable buffer of two newlines to acheive
+	 that.  */
+      static uchar newlines[] = "\n\n";
+      cpp_push_buffer (pfile, newlines, 2, true);
+
+      cpp_buffer *buffer
+	= cpp_push_buffer (pfile, reinterpret_cast<unsigned char *> (buf),
+			   strlen (buf), true);
+      buffer->to_free = buffer->buf;
+
+      file->header_unit = +1;
+      _cpp_mark_file_once_only (pfile, file);
+    }
+  else
+    {
+      /* Not a header unit, and we know it.  */
+      file->header_unit = -1;
+
+      if (!read_file (pfile, file, loc))
+	return false;
+
+      if (!has_unique_contents (pfile, file, type == IT_IMPORT, loc))
+	return false;
+
+      if (pfile->buffer && file->dir)
+	sysp = MAX (pfile->buffer->sysp, file->dir->sysp);
+
+      /* Add the file to the dependencies on its first inclusion.  */
+      if (CPP_OPTION (pfile, deps.style) > (sysp != 0)
+	  && !file->stack_count
+	  && file->path[0]
+	  && !(file->main_file && CPP_OPTION (pfile, deps.ignore_main_file)))
+	deps_add_dep (pfile->deps, file->path);
+
+      /* Clear buffer_valid since _cpp_clean_line messes it up.  */
+      file->buffer_valid = false;
+      file->stack_count++;
+
+      /* Stack the buffer.  */
+      cpp_buffer *buffer
+	= cpp_push_buffer (pfile, file->buffer, file->st.st_size,
+			   CPP_OPTION (pfile, preprocessed)
+			   && !CPP_OPTION (pfile, directives_only));
+      buffer->file = file;
+      buffer->sysp = sysp;
+      buffer->main_file = (type >= IT_HEADER_HWM
+			   && !CPP_OPTION (pfile, main_search));
+      buffer->to_free = file->buffer_start;
+
+      /* Initialize controlling macro state.  */
+      pfile->mi_valid = true;
+      pfile->mi_cmacro = 0;
+    }
 
   /* In the case of a normal #include, we're now at the start of the
      line *following* the #include.  A separate location_t for this
@@ -941,19 +980,30 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
 
      This does not apply if we found a PCH file, we're not a regular
      include, or we ran out of locations.  */
-  if (file->pchname == NULL
-      && type < IT_DIRECTIVE_HWM
-      && pfile->line_table->highest_location != LINE_MAP_MAX_LOCATION - 1)
+  bool decrement = (file->pchname == NULL
+		    && type < IT_DIRECTIVE_HWM
+		    && (pfile->line_table->highest_location
+			!= LINE_MAP_MAX_LOCATION - 1));
+  if (decrement)
     pfile->line_table->highest_location--;
 
-  /* Add line map and do callbacks.  */
-  _cpp_do_file_change (pfile, LC_ENTER, file->path,
+  if (file->header_unit <= 0)
+    /* Add line map and do callbacks.  */
+    _cpp_do_file_change (pfile, LC_ENTER, file->path,
 		       /* With preamble injection, start on line zero,
 			  so the preamble doesn't appear to have been
 			  included from line 1.  Likewise when
 			  starting preprocessed, we expect an initial
 			  locating line.  */
-		       type == IT_PRE_MAIN ? 0 : 1, sysp);
+			 type == IT_PRE_MAIN ? 0 : 1, sysp);
+  else if (decrement)
+    {
+      /* Adjust the line back one so we appear on the #include line itself.  */
+      const line_map_ordinary *map
+	= LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table);
+      linenum_type line = SOURCE_LINE (map, pfile->line_table->highest_line);
+      linemap_line_start (pfile->line_table, line - 1, 0);
+    }
 
   return true;
 }
@@ -1058,6 +1108,65 @@ _cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets,
   return _cpp_stack_file (pfile, file, type, loc);
 }
 
+/* NAME is a header file name, find the path we'll use to open it.  */
+
+const char *
+cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle,
+		      location_t loc)
+{
+  cpp_dir *dir = search_path_head (pfile, name, angle, IT_INCLUDE);
+  if (!dir)
+    return NULL;
+
+  _cpp_file *file = _cpp_find_file (pfile, name, dir, angle,
+				    _cpp_FFK_NORMAL, loc);
+  if (!file)
+    return NULL;
+
+  if (file->fd > 0)
+    {
+      /* Don't leave it open.  */
+      close (file->fd);
+      file->fd = 0;
+    }
+
+  file->header_unit = +1;
+  _cpp_mark_file_once_only (pfile, file);
+  return file->path;
+}
+
+/* Retrofit the just-entered main file asif it was an include.  This
+   will permit correct include_next use, and mark it as a system
+   header if that's where it resides.  We use filesystem-appropriate
+   prefix matching of the include path to locate the main file.  */
+void
+cpp_retrofit_as_include (cpp_reader *pfile)
+{
+  /* We should be the outermost.  */
+  gcc_assert (!pfile->buffer->prev);
+
+  if (const char *name = pfile->main_file->name)
+    {
+      /* Locate name on the include dir path, using a prefix match.  */
+      size_t name_len = strlen (name);
+      for (cpp_dir *dir = pfile->quote_include; dir; dir = dir->next)
+	if (dir->len < name_len
+	    && IS_DIR_SEPARATOR (name[dir->len])
+	    && !filename_ncmp (name, dir->name, dir->len))
+	  {
+	    pfile->main_file->dir = dir;
+	    pfile->buffer->main_file = false;
+	    if (dir->sysp)
+	      cpp_make_system_header (pfile, 1, 0);
+	    break;
+	  }
+    }
+
+  /* Initialize controlling macro state.  */
+  pfile->mi_valid = true;
+  pfile->mi_cmacro = 0;
+}
+
 /* Could not open FILE.  The complication is dependency output.  */
 static void
 open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets,

