From 9844497a935d5e89dc92539128edccb6bb408bb1 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 19 Nov 2020 07:00:51 -0800 Subject: [PATCH] preprocessor: main file searching This adds the capability to locate the main file on the user or system include paths. That's extremely useful to users building header units. Searching has to be requiested (plain header-unit compilation will not search). Also, to make include_next work as expected when building a header unit, we add a mechanism to retrofit a non-searched source file as one on the include path. libcpp/ * include/cpplib.h (enum cpp_main_search): New. (struct cpp_options): Add main_search field. (cpp_main_loc): Declare. (cpp_retrofit_as_include): Declare. * internal.h (struct cpp_reader): Add main_loc field. (_cpp_in_main_source_file): Not main if main is a header. * init.c (cpp_read_main_file): Use main_search option to locate main file. Set main_loc * files.c (cpp_retrofit_as_include): New. --- libcpp/files.c | 31 +++++++++++++++++++++++++++++++ libcpp/include/cpplib.h | 15 +++++++++++++++ libcpp/init.c | 21 ++++++++++++++++++--- libcpp/internal.h | 7 ++++++- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/libcpp/files.c b/libcpp/files.c index ba52d2b..301b237 100644 --- a/libcpp/files.c +++ b/libcpp/files.c @@ -1131,6 +1131,37 @@ cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle, 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; + 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, diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 630f2e0..91226cf 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -308,6 +308,15 @@ enum cpp_normalize_level { normalized_none }; +enum cpp_main_search +{ + CMS_none, /* A regular source file. */ + CMS_header, /* Is a directly-specified header file (eg PCH or + header-unit). */ + CMS_user, /* Search the user INCLUDE path. */ + CMS_system, /* Search the system INCLUDE path. */ +}; + /* This structure is nested inside struct cpp_reader, and carries all the options visible to the command line. */ struct cpp_options @@ -566,6 +575,8 @@ struct cpp_options /* The maximum depth of the nested #include. */ unsigned int max_include_depth; + + cpp_main_search main_search : 8; }; /* Diagnostic levels. To get a diagnostic without associating a @@ -997,6 +1008,10 @@ extern const char *cpp_find_header_unit (cpp_reader *, const char *file, too. If there was an error opening the file, it returns NULL. */ extern const char *cpp_read_main_file (cpp_reader *, const char *, bool injecting = false); +extern location_t cpp_main_loc (const cpp_reader *); + +/* Adjust for the main file to be an include. */ +extern void cpp_retrofit_as_include (cpp_reader *); /* Set up built-ins with special behavior. Use cpp_init_builtins() instead unless your know what you are doing. */ diff --git a/libcpp/init.c b/libcpp/init.c index fc82658..f77dc26 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -675,8 +675,14 @@ cpp_read_main_file (cpp_reader *pfile, const char *fname, bool injecting) deps_add_default_target (deps, fname); pfile->main_file - = _cpp_find_file (pfile, fname, &pfile->no_search_path, /*angle=*/0, - _cpp_FFK_NORMAL, 0); + = _cpp_find_file (pfile, fname, + CPP_OPTION (pfile, preprocessed) ? &pfile->no_search_path + : CPP_OPTION (pfile, main_search) == CMS_user + ? pfile->quote_include + : CPP_OPTION (pfile, main_search) == CMS_system + ? pfile->bracket_include : &pfile->no_search_path, + /*angle=*/0, _cpp_FFK_NORMAL, 0); + if (_cpp_find_failed (pfile->main_file)) return NULL; @@ -698,7 +704,16 @@ cpp_read_main_file (cpp_reader *pfile, const char *fname, bool injecting) LINEMAP_LINE (last), LINEMAP_SYSP (last)); } - return ORDINARY_MAP_FILE_NAME (LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table)); + auto *map = LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table); + pfile->main_loc = MAP_START_LOCATION (map); + + return ORDINARY_MAP_FILE_NAME (map); +} + +location_t +cpp_main_loc (const cpp_reader *pfile) +{ + return pfile->main_loc; } /* For preprocessed files, if the very first characters are diff --git a/libcpp/internal.h b/libcpp/internal.h index e629cbc..697fef0 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -591,6 +591,10 @@ struct cpp_reader /* If non-zero, the lexer will use this location for the next token instead of getting a location from the linemap. */ location_t forced_token_location; + + /* Location identifying the main source file -- intended to be line + zero of said file. */ + location_t main_loc; }; /* Character classes. Based on the more primitive macros in safe-ctype.h. @@ -643,7 +647,8 @@ _cpp_in_system_header (cpp_reader *pfile) inline int _cpp_in_main_source_file (cpp_reader *pfile) { - return pfile->buffer->file == pfile->main_file; + return (!CPP_OPTION (pfile, main_search) + && pfile->buffer->file == pfile->main_file); } /* True if NODE is a macro for the purposes of ifdef, defined etc. */ -- 2.7.4