Tested x86_64-pc-linux-gnu. Any comments?
-- 8< --
Since the standard library doesn't preclude an #include of a standard
library header from bringing in declarations from other headers, we can
translate an #include of any of the importable headers as an import of
<bits/stdc++.h>.
To reduce the amount of C++ standard knowledge encoded in libcpp, I extend
the translate_include callback to allow it to suggest an alternate header to
try translating. It's a bit awkward to bounce back and forth, but this
seems like the right division of responsibilities.
libcpp/ChangeLog:
* include/cpplib.h (struct cpp_callbacks): Replace 'path' parameter
with file, angle_brackets, and alternate name.
(cpp_get_name): Declare.
* files.cc (cpp_get_name): New.
(_cpp_stack_include, _cpp_post_stack_file, _cpp_stack_file)
(_cpp_stack_translated_file): Refactor, try alternate file.
gcc/cp/ChangeLog:
* module.cc (maybe_translate_include): Suggest <bits/stdc++.h>
as an alternate for importable standard library headers.
(importable_headers, is_importable_header): New.
---
libcpp/include/cpplib.h | 4 +-
gcc/cp/module.cc | 80 ++++++++++++++++-
libcpp/files.cc | 189 ++++++++++++++++++++++++----------------
3 files changed, 195 insertions(+), 78 deletions(-)
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 5190ff7d08f..d38889b893e 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -860,7 +860,8 @@ struct cpp_callbacks
/* Maybe translate a #include into something else. Return a
cpp_buffer containing the translation if translating. */
char *(*translate_include) (cpp_reader *, line_maps *, location_t,
- const char *path);
+ _cpp_file *file, bool angle_brackets,
+ const char **alternate);
};
#ifdef VMS
@@ -1564,6 +1565,7 @@ extern bool cpp_push_include (cpp_reader *, const char *);
extern bool cpp_push_default_include (cpp_reader *, const char *);
extern void cpp_change_file (cpp_reader *, enum lc_reason, const char *);
extern const char *cpp_get_path (struct _cpp_file *);
+extern const char *cpp_get_name (struct _cpp_file *);
extern cpp_dir *cpp_get_dir (struct _cpp_file *);
extern cpp_buffer *cpp_get_buffer (cpp_reader *);
extern struct _cpp_file *cpp_get_file (cpp_buffer *);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 45a0309b86e..a9c40212434 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -22488,11 +22488,66 @@ void module_state::set_filename (const Cody::Packet
&packet)
}
}
+/* The list of importable headers from C++ Table 24. */
+
+static const char *
+importable_headers[] =
+ {
+ "algorithm", "any", "array", "atomic",
+ "barrier", "bit", "bitset",
+ "charconv", "chrono", "compare", "complex", "concepts",
+ "condition_variable", "contracts", "coroutine",
+ "debugging", "deque",
+ "exception", "execution", "expected",
+ "filesystem", "flat_map", "flat_set", "format", "forward_list",
+ "fstream", "functional", "future",
+ "generator",
+ "hazard_pointer", "hive",
+ "initializer_list", "inplace_vector", "iomanip", "ios", "iosfwd",
+ "iostream", "istream", "iterator",
+ "latch", "limits", "linalg", "list", "locale",
+ "map", "mdspan", "memory", "memory_resource", "meta", "mutex",
+ "new", "numbers", "numeric",
+ "optional", "ostream",
+ "print",
+ "queue",
+ "random", "ranges", "ratio", "rcu", "regex",
+ "scoped_allocator", "semaphore", "set", "shared_mutex", "simd",
+ "source_location", "span", "spanstream", "sstream", "stack", "stacktrace",
+ "stdexcept", "stdfloat", "stop_token", "streambuf", "string",
+ "string_view", "syncstream", "system_error",
+ "text_encoding", "thread", "tuple", "type_traits", "typeindex", "typeinfo",
+ "unordered_map", "unordered_set",
+ "utility",
+ "valarray", "variant", "vector", "version"
+ };
+
+/* True iff <name> is listed as an importable standard header. */
+
+static bool
+is_importable_header (const char *name)
+{
+ unsigned lo = 0;
+ unsigned hi = ARRAY_SIZE (importable_headers);
+ while (hi > lo)
+ {
+ unsigned mid = (lo + hi)/2;
+ int cmp = strcmp (name, importable_headers[mid]);
+ if (cmp > 0)
+ lo = mid + 1;
+ else if (cmp < 0)
+ hi = mid;
+ else
+ return true;
+ }
+ return false;
+}
+
/* Figure out whether to treat HEADER as an include or an import. */
static char *
maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc,
- const char *path)
+ _cpp_file *file, bool angle, const char **alternate)
{
if (!modules_p ())
{
@@ -22501,6 +22556,8 @@ maybe_translate_include (cpp_reader *reader, line_maps
*lmaps, location_t loc,
return nullptr;
}
+ const char *path = cpp_get_path (file);
+
dump.push (NULL);
dump () && dump ("Checking include translation '%s'", path);
@@ -22546,6 +22603,27 @@ maybe_translate_include (cpp_reader *reader, line_maps
*lmaps, location_t loc,
if (!strcmp ((*note_includes)[ix], path))
note = true;
+ /* Maybe try importing a different header instead. */
+ if (alternate && translate == xlate_kind::unknown)
+ {
+ const char *fname = cpp_get_name (file);
+ /* Redirect importable <name> to <bits/stdc++.h>. */
+ /* ??? Generalize to use a .json. */
+ expanded_location eloc = expand_location (loc);
+ if (angle && is_importable_header (fname)
+ /* Exclude #include <version> which often goes with import std. */
+ && strcmp (fname, "version") != 0
+ /* Don't redirect #includes between library headers; if the import
+ brings in the current file we then get redefinition errors. */
+ && !strstr (eloc.file, cpp_get_dir (file)->name)
+ /* ??? These are needed when running a toolchain from the build
+ directory, because libsupc++ headers aren't linked into
+ libstdc++-v3/include with the other headers. */
+ && !strstr (eloc.file, "libstdc++-v3/include")
+ && !strstr (eloc.file, "libsupc++"))
+ *alternate = "bits/stdc++.h";
+ }
+
if (note)
inform (loc, translate == xlate_kind::import
? G_("include %qs translated to import")
diff --git a/libcpp/files.cc b/libcpp/files.cc
index d80c4bfd907..a28f1622ced 100644
--- a/libcpp/files.cc
+++ b/libcpp/files.cc
@@ -946,6 +946,42 @@ has_unique_contents (cpp_reader *pfile, _cpp_file *file,
bool import,
return true;
}
+static void _cpp_post_stack_file (cpp_reader *, _cpp_file *, include_type,
bool);
+
+static bool
+_cpp_stack_translated_file (cpp_reader *pfile, _cpp_file *file,
+ char *buf, include_type type)
+{
+ /* 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. (We also need an extra newline, so this looks like a regular
+ file, which we do that to to make sure we don't fall off the end in the
+ middle of a line. */
+ if (type != IT_CMDLINE)
+ {
+ static uchar newlines[] = "\n\n\n";
+ cpp_push_buffer (pfile, newlines, 2, true);
+ }
+
+ size_t len = strlen (buf);
+ buf[len] = '\n'; /* See above */
+ cpp_buffer *buffer
+ = cpp_push_buffer (pfile, reinterpret_cast<unsigned char *> (buf),
+ len, true);
+ buffer->to_free = buffer->buf;
+ if (type == IT_CMDLINE)
+ /* Tell _cpp_pop_buffer to change files. */
+ buffer->file = file;
+
+ file->header_unit = +1;
+ _cpp_mark_file_once_only (pfile, file);
+
+ _cpp_post_stack_file (pfile, file, type, false);
+ return true;
+}
+
/* Place the file referenced by FILE into a new buffer on the buffer
stack if possible. Returns true if a buffer is stacked. Use LOC
for any diagnostics. */
@@ -954,88 +990,53 @@ bool
_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
location_t loc)
{
- if (is_known_idempotent_file (pfile, file, type == IT_IMPORT))
+ int sysp = 0;
+
+ /* Not a header unit, and we know it. */
+ file->header_unit = -1;
+
+ 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));
+ if (pfile->buffer && file->dir)
+ sysp = MAX (pfile->buffer->sysp, file->dir->sysp);
- 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. (We also need an extra newline, so this looks like a regular
- file, which we do that to to make sure we don't fall off the end in the
- middle of a line. */
- if (type != IT_CMDLINE)
- {
- static uchar newlines[] = "\n\n\n";
- cpp_push_buffer (pfile, newlines, 2, true);
- }
+ /* Add the file to the dependencies on its first inclusion. */
+ if (CPP_OPTION (pfile, deps.style) > (sysp != 0)
+ && !file->stack_count
+ && file->path[0]
+ && !(pfile->main_file == file
+ && CPP_OPTION (pfile, deps.ignore_main_file)))
+ deps_add_dep (pfile->deps, file->path);
- size_t len = strlen (buf);
- buf[len] = '\n'; /* See above */
- cpp_buffer *buffer
- = cpp_push_buffer (pfile, reinterpret_cast<unsigned char *> (buf),
- len, true);
- buffer->to_free = buffer->buf;
- if (type == IT_CMDLINE)
- /* Tell _cpp_pop_buffer to change files. */
- buffer->file = file;
+ /* Clear buffer_valid since _cpp_clean_line messes it up. */
+ file->buffer_valid = false;
+ file->stack_count++;
- file->header_unit = +1;
- _cpp_mark_file_once_only (pfile, file);
- }
- else
- {
- /* Not a header unit, and we know it. */
- file->header_unit = -1;
+ /* 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;
- if (!read_file (pfile, file, loc))
- return false;
+ /* Initialize controlling macro state. */
+ pfile->mi_valid = true;
+ pfile->mi_cmacro = 0;
- 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]
- && !(pfile->main_file == 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;
- }
+ _cpp_post_stack_file (pfile, file, type, sysp);
+ return true;
+}
+static void
+_cpp_post_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
+ bool sysp)
+{
/* 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
location makes no sense, until we do the LC_LEAVE.
@@ -1070,8 +1071,6 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file,
include_type type,
linenum_type line = SOURCE_LINE (map, pfile->line_table->highest_line);
linemap_line_start (pfile->line_table, line - 1, 0);
}
-
- return true;
}
/* Mark FILE to be included once only. */
@@ -1171,7 +1170,37 @@ _cpp_stack_include (cpp_reader *pfile, const char
*fname, int angle_brackets,
if (type == IT_DEFAULT && file == NULL)
return false;
- return _cpp_stack_file (pfile, file, type, loc);
+ if (is_known_idempotent_file (pfile, file, type == IT_IMPORT))
+ return false;
+
+ /* Check C++ module include translation. */
+ char *buf = nullptr;
+ if (!file->header_unit && type < IT_DEFAULT
+ /* Do not include translate include-next. */
+ && type != IT_INCLUDE_NEXT
+ && pfile->cb.translate_include)
+ {
+ const char *aname = nullptr;
+ buf = (pfile->cb.translate_include
+ (pfile, pfile->line_table, loc, file,
+ angle_brackets, &aname));
+ if (!buf && aname)
+ {
+ _cpp_file *afile = _cpp_find_file (pfile, aname, dir, angle_brackets,
+ _cpp_FFK_NORMAL, loc);
+ if (afile && !afile->header_unit)
+ buf = (pfile->cb.translate_include
+ (pfile, pfile->line_table, loc,
+ afile, angle_brackets, nullptr));
+ if (buf)
+ file = afile;
+ }
+ }
+
+ if (buf)
+ return _cpp_stack_translated_file (pfile, file, buf, type);
+ else
+ return _cpp_stack_file (pfile, file, type, loc);
}
/* NAME is a header file name, find the _cpp_file, if any. */
@@ -2584,6 +2613,14 @@ cpp_get_path (struct _cpp_file *f)
return f->path;
}
+/* Get the base name specified in the directive. */
+
+const char *
+cpp_get_name (struct _cpp_file *f)
+{
+ return f->name;
+}
+
/* Get the directory associated with the _cpp_file F. */
cpp_dir *
base-commit: aaa625a51cff750b40bc98f6555adc3f3f5f297b
--
2.51.0