c++: header-unit build capability [PR 99023]
authorNathan Sidwell <nathan@acm.org>
Thu, 18 Feb 2021 20:46:25 +0000 (12:46 -0800)
committerNathan Sidwell <nathan@acm.org>
Thu, 18 Feb 2021 21:22:48 +0000 (13:22 -0800)
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
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/modules/modules.exp
gcc/testsuite/g++.dg/modules/pr99023_a.X [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99023_b.X [new file with mode: 0644]
libcpp/files.c
libcpp/include/cpplib.h
libcpp/internal.h
libcpp/macro.c

index 064e57a29c417c3efc4aab20caef2ce609e6d191..e801c52069ec083c2ff30b5bbe93a1eeb9b19aaf 100644 (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;
       }
index e8baa545eee95bfa43111b61acbcbb280ae86f29..c00514a6306ac50a59e8e4a9f523c0588fa714b5 100644 (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
index c17120f2c006a8eec42016ab96382513c5ddb0b4..38654caf7b9ac3dd740c98a8f721fbe4ff5a6d93 100644 (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
        }
     }
 }
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X b/gcc/testsuite/g++.dg/modules/pr99023_a.X
new file mode 100644 (file)
index 0000000..c872d15
--- /dev/null
@@ -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 (file)
index 0000000..3d82f34
--- /dev/null
@@ -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
index 3a35f7c9743aa2fd0284a2444e40bf1a077da2f1..6e20fc5887f001d23179eda88c5de323f24571a1 100644 (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.  */
 
-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
index 17feb648ebe8e540ddb8d9be85fcfe74ad711731..41d75d9e731b6225a5c1bdc651a95e82914bea5f 100644 (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.  */
index 32f9f508562c4ab09ade3b3da1e44eb334f76980..fd44de6b8f0f9a7fd70a589fdb9a2d6a00170363 100644 (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,
index fa6acfff771f2ed582b0dc0ee2e7044fcc6a5d9b..dff7c98a4df50a0e103a7bd7cecb9354cd41513f 100644 (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);