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.
This commit is contained in:
Nathan Sidwell 2021-02-18 12:46:25 -08:00
parent d82f829905
commit 1f9db6929d
9 changed files with 102 additions and 49 deletions

View File

@ -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;
}

View File

@ -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{<system>} it will be resolved to a
specific user or system header using the include path.
@item -stdlib=@var{libstdc++,libc++}
@opindex stdlib

View File

@ -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
}
}
}

View File

@ -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

View File

@ -0,0 +1,7 @@
// PR c++/99023, ICE
// { dg-additional-options {-x c++-system-header iostream -fmodules-ts -flang-info-include-translate=<initializer_list> --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

View File

@ -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. */
static _cpp_file *
test_header_unit (cpp_reader *pfile, const char *name, bool angle,
location_t loc)
{
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;
}
/* NAME is a header file name, find the path we'll use to open it and infer that
it is a header-unit. */
const char *
cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle,
location_t loc)
_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)
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

View File

@ -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. */

View File

@ -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,

View File

@ -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);