c++: header-unit build capability [PR 99023]

Message ID c285f971-c233-fba7-27b4-9c1feecf7a0e@acm.org
State New
Headers show
Series
  • c++: header-unit build capability [PR 99023]
Related show

Commit Message

Nathan Sidwell Feb. 18, 2021, 9:22 p.m.
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.

-- 
Nathan Sidwell

Patch

diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index 064e57a29c4..e801c52069e 100644
--- c/gcc/cp/module.cc
+++ w/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 c/gcc/doc/invoke.texi w/gcc/doc/invoke.texi
index e8baa545eee..c00514a6306 100644
--- c/gcc/doc/invoke.texi
+++ w/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{<system>} it will be resolved to a
+specific user or system header using the include path.
 
 @item -stdlib=@var{libstdc++,libc++}
 @opindex stdlib
diff --git c/gcc/testsuite/g++.dg/modules/modules.exp w/gcc/testsuite/g++.dg/modules/modules.exp
index c17120f2c00..38654caf7b9 100644
--- c/gcc/testsuite/g++.dg/modules/modules.exp
+++ w/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 c/gcc/testsuite/g++.dg/modules/pr99023_a.X w/gcc/testsuite/g++.dg/modules/pr99023_a.X
new file mode 100644
index 00000000000..c872d15f792
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/pr99023_b.X w/gcc/testsuite/g++.dg/modules/pr99023_b.X
new file mode 100644
index 00000000000..3d82f34868b
--- /dev/null
+++ w/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=<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
diff --git c/libcpp/files.c w/libcpp/files.c
index 3a35f7c9743..6e20fc5887f 100644
--- c/libcpp/files.c
+++ w/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 c/libcpp/include/cpplib.h w/libcpp/include/cpplib.h
index 17feb648ebe..41d75d9e731 100644
--- c/libcpp/include/cpplib.h
+++ w/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 c/libcpp/internal.h w/libcpp/internal.h
index 32f9f508562..fd44de6b8f0 100644
--- c/libcpp/internal.h
+++ w/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 c/libcpp/macro.c w/libcpp/macro.c
index fa6acfff771..dff7c98a4df 100644
--- c/libcpp/macro.c
+++ w/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);