From 1f9db6929d926222aee0628b93f77cd20cf3adc4 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 18 Feb 2021 12:46:25 -0800 Subject: [PATCH] c++: header-unit build capability [PR 99023] This defect really required building header-units and include translation of pieces of the standard library. This adds smarts to the modules test harness to do that -- accept .X files as the source file, but provide '-x c++-system-header $HDR' in the options. The .X file will be considered by the driver to be a linker script and ignored (with a warning). Using this we can add 2 tests that end up building list_initializer and iostream, along with a test that iostream's build include-translates list_initializer's #include. That discovered a set of issues with the -flang-info-include-translate=HDR handling, also fixed and documented here. PR c++/99023 gcc/cp/ * module.cc (canonicalize_header_name): Use cpp_probe_header_unit. (maybe_translate_include): Fix note_includes comparison. (init_modules): Fix note_includes string termination. libcpp/ * include/cpplib.h (cpp_find_header_unit): Rename to ... (cpp_probe_header_unit): ... this. * internal.h (_cp_find_header_unit): Declare. * files.c (cpp_find_header_unit): Break apart to .. (test_header_unit): ... this, and ... (_cpp_find_header_unit): ... and, or and ... (cpp_probe_header_unit): ... this. * macro.c (cpp_get_token_1): Call _cpp_find_header_unit. gcc/ * doc/invoke.texi (flang-info-include-translate): Document header lookup behaviour. gcc/testsuite/ * g++.dg/modules/modules.exp: Bail on cross-testing. Add support for .X files. * g++.dg/modules/pr99023_a.X: New. * g++.dg/modules/pr99023_b.X: New. --- gcc/cp/module.cc | 22 +++------ gcc/doc/invoke.texi | 7 ++- gcc/testsuite/g++.dg/modules/modules.exp | 40 +++++++++++----- gcc/testsuite/g++.dg/modules/pr99023_a.X | 6 +++ gcc/testsuite/g++.dg/modules/pr99023_b.X | 7 +++ libcpp/files.c | 59 ++++++++++++++++-------- libcpp/include/cpplib.h | 4 +- libcpp/internal.h | 2 + libcpp/macro.c | 2 +- 9 files changed, 101 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/pr99023_a.X create mode 100644 gcc/testsuite/g++.dg/modules/pr99023_b.X diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 064e57a29c4..e801c52069e 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19091,7 +19091,7 @@ canonicalize_header_name (cpp_reader *reader, location_t loc, bool unquoted, buf[len] = 0; if (const char *hdr - = cpp_find_header_unit (reader, buf, str[-1] == '<', loc)) + = cpp_probe_header_unit (reader, buf, str[-1] == '<', loc)) { len = strlen (hdr); str = hdr; @@ -19185,19 +19185,11 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, else if (note_include_translate_no && xlate == 0) note = true; else if (note_includes) - { - /* We do not expect the note_includes vector to be large, so O(N) - iteration. */ - for (unsigned ix = note_includes->length (); !note && ix--;) - { - const char *hdr = (*note_includes)[ix]; - size_t hdr_len = strlen (hdr); - if ((hdr_len == len - || (hdr_len < len && IS_DIR_SEPARATOR (path[len - hdr_len - 1]))) - && !memcmp (hdr, path + len - hdr_len, hdr_len)) - note = true; - } - } + /* We do not expect the note_includes vector to be large, so O(N) + iteration. */ + for (unsigned ix = note_includes->length (); !note && ix--;) + if (!strcmp ((*note_includes)[ix], path)) + note = true; if (note) inform (loc, xlate @@ -19570,7 +19562,7 @@ init_modules (cpp_reader *reader) 0, !delimed, hdr, len); char *path = XNEWVEC (char, len + 1); memcpy (path, hdr, len); - path[len+1] = 0; + path[len] = 0; (*note_includes)[ix] = path; } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e8baa545eee..c00514a6306 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3382,7 +3382,12 @@ is used when building the C++ library.) @itemx -flang-info-include-translate=@var{header} @opindex flang-info-include-translate @opindex flang-info-include-translate-not -Diagnose include translation events. +Diagnose include translation events. The first will note accepted +include translations, the second will note declined include +translations. The @var{header} form will inform of include +translations relating to that specific header. If @var{header} is of +the form @code{"user"} or @code{} it will be resolved to a +specific user or system header using the include path. @item -stdlib=@var{libstdc++,libc++} @opindex stdlib diff --git a/gcc/testsuite/g++.dg/modules/modules.exp b/gcc/testsuite/g++.dg/modules/modules.exp index c17120f2c00..38654caf7b9 100644 --- a/gcc/testsuite/g++.dg/modules/modules.exp +++ b/gcc/testsuite/g++.dg/modules/modules.exp @@ -39,6 +39,11 @@ set MOD_STD_LIST { 17 2a } dg-init +if {[is_remote host]} { + # remote testing not functional here :( + return +} + global module_do global module_cmis @@ -274,6 +279,9 @@ proc module-init { src } { return $option_list } +# cleanup any detritus from previous run +cleanup_module_files [find $DEFAULT_REPO *.gcm] + # not grouped tests, sadly tcl doesn't have negated glob foreach test [prune [lsort [find $srcdir/$subdir {*.[CH]}]] \ "$srcdir/$subdir/*_?.\[CH\]"] { @@ -282,6 +290,7 @@ foreach test [prune [lsort [find $srcdir/$subdir {*.[CH]}]] \ set std_list [module-init $test] foreach std $std_list { + global module_cmis set module_cmis {} verbose "Testing $nshort $std" 1 dg-test $test "$std" $DEFAULT_MODFLAGS @@ -292,11 +301,11 @@ foreach test [prune [lsort [find $srcdir/$subdir {*.[CH]}]] \ } # grouped tests -foreach src [lsort [find $srcdir/$subdir {*_a.[CH}]] { +foreach src [lsort [find $srcdir/$subdir {*_a.[CHX}]] { # use the FOO_a.C name as the parallelization key if [runtest_file_p $runtests $src] { set tests [lsort [find [file dirname $src] \ - [regsub {_a.[CH]$} [file tail $src] {_[a-z].[CH]}]]] + [regsub {_a.[CHX]$} [file tail $src] {_[a-z].[CHX]}]]] set std_list [module-init $src] foreach std $std_list { @@ -304,30 +313,39 @@ foreach src [lsort [find $srcdir/$subdir {*_a.[CH}]] { global module_do set module_do {"compile" "P"} set asm_list {} + set any_hdrs 0 + global DEFAULT_REPO + file_on_host delete $DEFAULT_REPO foreach test $tests { if { [lindex $module_do 1] != "N" } { + global module_cmis set module_cmis {} set nshort [file tail [file dirname $test]]/[file tail $test] verbose "Testing $nshort $std" 1 - if { [file extension $test] == ".C" } { - lappend asm_list [file rootname [file tail $test]].s + switch [file extension $test] { + ".C" { + lappend asm_list [file rootname [file tail $test]].s + } + ".X" { + set any_hdrs 1 + } } dg-test -keep-output $test "$std" $DEFAULT_MODFLAGS set testcase [string range $test [string length "$srcdir/"] end] lappend mod_files [module_cmi_p $testcase $module_cmis] } } - set ok 1 set testcase [regsub {_a.[CH]} $src {}] set testcase \ [string range $testcase [string length "$srcdir/"] end] - set ok [module_do_it $module_do $testcase $std $asm_list] - if { $ok } { - foreach asm $asm_list { - file_on_host delete $asm - } - cleanup_module_files $mod_files + module_do_it $module_do $testcase $std $asm_list + foreach asm $asm_list { + file_on_host delete $asm + } + if { $any_hdrs } { + set mod_files [find $DEFAULT_REPO *.gcm] } + cleanup_module_files $mod_files } } } diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X b/gcc/testsuite/g++.dg/modules/pr99023_a.X new file mode 100644 index 00000000000..c872d15f792 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X @@ -0,0 +1,6 @@ +// PR c++/99023, ICE +// { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts --param ggc-min-expand=0} } + +// { dg-prune-output {linker input file unused} } + +NO DO NOT COMPILE diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X b/gcc/testsuite/g++.dg/modules/pr99023_b.X new file mode 100644 index 00000000000..3d82f34868b --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X @@ -0,0 +1,7 @@ +// PR c++/99023, ICE +// { dg-additional-options {-x c++-system-header iostream -fmodules-ts -flang-info-include-translate= --param ggc-min-expand=0} } + +// { dg-prune-output {linker input file unused} } + +// { dg-regexp {[^\n]*: note: include '[^\n]*/initializer_list' translated to import\n} } +NO DO NOT COMPILE diff --git a/libcpp/files.c b/libcpp/files.c index 3a35f7c9743..6e20fc5887f 100644 --- a/libcpp/files.c +++ b/libcpp/files.c @@ -1108,31 +1108,54 @@ _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. */ +/* NAME is a header file name, find the _cpp_file, if any. */ -const char * -cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle, - location_t loc) +static _cpp_file * +test_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; + if (cpp_dir *dir = search_path_head (pfile, name, angle, IT_INCLUDE)) + return _cpp_find_file (pfile, name, dir, angle, _cpp_FFK_NORMAL, loc); + + return nullptr; +} - _cpp_file *file = _cpp_find_file (pfile, name, dir, angle, - _cpp_FFK_NORMAL, loc); - if (!file) - return NULL; +/* NAME is a header file name, find the path we'll use to open it and infer that + it is a header-unit. */ - if (file->fd > 0) +const char * +_cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle, + location_t loc) +{ + if (_cpp_file *file = test_header_unit (pfile, name, angle, loc)) { - /* Don't leave it open. */ - close (file->fd); - file->fd = 0; + 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; } - file->header_unit = +1; - _cpp_mark_file_once_only (pfile, file); - return file->path; + return nullptr; +} + +/* NAME is a header file name, find the path we'll use to open it. But do not + infer it is a header unit. */ + +const char * +cpp_probe_header_unit (cpp_reader *pfile, const char *name, bool angle, + location_t loc) +{ + if (_cpp_file *file = test_header_unit (pfile, name, angle, loc)) + return file->path; + + return nullptr; } /* Retrofit the just-entered main file asif it was an include. This diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 17feb648ebe..41d75d9e731 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -1012,8 +1012,8 @@ 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); +extern const char *cpp_probe_header_unit (cpp_reader *, const char *file, + bool angle_p, location_t); /* Call these to get name data about the various compile-time charsets. */ diff --git a/libcpp/internal.h b/libcpp/internal.h index 32f9f508562..fd44de6b8f0 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -703,6 +703,8 @@ extern _cpp_file *_cpp_find_file (cpp_reader *, const char *, cpp_dir *, int angle, _cpp_find_file_kind, location_t); extern bool _cpp_find_failed (_cpp_file *); extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *); +extern const char *_cpp_find_header_unit (cpp_reader *, const char *file, + bool angle_p, location_t); extern void _cpp_fake_include (cpp_reader *, const char *); extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, include_type, location_t); extern bool _cpp_stack_include (cpp_reader *, const char *, int, diff --git a/libcpp/macro.c b/libcpp/macro.c index fa6acfff771..dff7c98a4df 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -3010,7 +3010,7 @@ cpp_get_token_1 (cpp_reader *pfile, location_t *location) if (need_search) { - found = cpp_find_header_unit (pfile, fname, angle, tmp->src_loc); + found = _cpp_find_header_unit (pfile, fname, angle, tmp->src_loc); if (!found) found = ""; len = strlen (found); -- 2.30.2