preprocessor: Add support for header unit translation
authorNathan Sidwell <nathan@acm.org>
Wed, 18 Nov 2020 16:27:16 +0000 (08:27 -0800)
committerNathan Sidwell <nathan@acm.org>
Wed, 18 Nov 2020 16:45:46 +0000 (08:45 -0800)
libcpp/
* files.c (struct _cpp_file): Add header_unit field.
(_cpp_stack_file): Add header unit support.
(cpp_find_header_unit): New.
* include/cpplib.h (cpp_find_header_unit): Declare.

libcpp/files.c
libcpp/include/cpplib.h

index d73177aa1eef229896c181fc1eb70dbb567edb87..b5d9f30297ed4ad9455a2f4926da65ee4dcf9ca1 100644 (file)
@@ -111,6 +111,9 @@ struct _cpp_file
 
   /* If this file is implicitly preincluded.  */
   bool implicit_preinclude : 1;
+
+  /* > 0: Known C++ Module header unit, <0: known not.  ==0, unknown  */
+  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,73 @@ _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;
+  int sysp = 0;
+  char *buf = nullptr;
 
-  if (!has_unique_contents (pfile, file, type == IT_IMPORT, loc))
-    return false;
+  /* 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));
 
-  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;
-
-  /* Initialize controlling macro state.  */
-  pfile->mi_valid = true;
-  pfile->mi_cmacro = 0;
+  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->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 +978,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 +1106,33 @@ _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;
+}
+
 /* Could not open FILE.  The complication is dependency output.  */
 static void
 open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets,
index 75d4d0a9f2ffd47c315846076c609633ace43baa..389af32bc5c1f358ea688494c3f90dcd3563928c 100644 (file)
@@ -983,6 +983,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