testsuite: Extend C++ struct-layout-1.exp testing to test C++14 vs. C++17 interoperab...
authorJakub Jelinek <jakub@redhat.com>
Tue, 21 Apr 2020 15:08:10 +0000 (17:08 +0200)
committerJakub Jelinek <jakub@redhat.com>
Tue, 21 Apr 2020 15:08:10 +0000 (17:08 +0200)
Jonathan reported an ABI incompatibility between C++14 and C++17 in
passing some aggregates with empty bases on aarch64 (and apparently on arm
too).

The following patch adds 3000 (by default) tests for such interoperability,
using the struct-layout-1* framework.  The current 3000 tests are generated
as is (so unchanged from previous ones), and afterwards there is another set
of 3000 ones, where always one of the tNNN_x.C and tNNN_y.C tests get added
-std=c++14 -DCXX14_VS_CXX17 and another one -std=c++17 -DCXX14_VS_CXX17
options (which one which is chosen pseudo-randomly), which causes the
structs to have an empty base.

I haven't added (yet) checks if the alternate compiler does support these
options (I think that can be done incrementally), so for now this testing is
done only if the alternate compiler is not used.

I had to fix a bug in the flexible array handling, because while we were
lucky in the 3000 generated tests not to have toplevel fields after field
with flexible array members, in the next 3000 we aren't lucky anymore.
But even with that change, diff -upr between old and new
testsuite/g++/g++.dg/g++.dg-struct-layout-1/ doesn't show any differences
except for the ^Only in... messages for the new tests in there.

Bootstrapped/regtested on x86_64-linux and i686-linux and additionally
tested on aarch64-linux, where
FAIL: tmpdir-g++.dg-struct-layout-1/t032 cp_compat_x_tst.o-cp_compat_y_tst.o execute
FAIL: tmpdir-g++.dg-struct-layout-1/t056 cp_compat_x_tst.o-cp_compat_y_tst.o execute
FAIL: tmpdir-g++.dg-struct-layout-1/t057 cp_compat_x_tst.o-cp_compat_y_tst.o execute
FAIL: tmpdir-g++.dg-struct-layout-1/t058 cp_compat_x_tst.o-cp_compat_y_tst.o execute
FAIL: tmpdir-g++.dg-struct-layout-1/t059 cp_compat_x_tst.o-cp_compat_y_tst.o execute
because of the backend bug, and with that bug fixed it succeeds.
Matthew has kindly tested it also on aarch64-linux and arm*-*.

The primary goal of the patch is catch if some targets other than aarch64 or
arm aren't affected too.

2020-04-21  Jakub Jelinek  <jakub@redhat.com>

PR c++/94383
* g++.dg/compat/struct-layout-1.exp: If !$use_alt, add -c to generator
args.
* g++.dg/compat/struct-layout-1_generate.c (dg_options): Add another
%s to the start of dg-options arg.
(cxx14_vs_cxx17, do_cxx14_vs_cxx17): New variables.
(switchfiles): If cxx14_vs_cxx17, prepend -std=c++14 -DCXX14_VS_CXX17
or -std=c++17 -DCXX17_VS_CXX14 - randomly - to dg-options.
(output): Don't append further fields once one with flexible array
member is added.
(generate_random_tests): Don't use toplevel unions if cxx14_vs_cxx17.
(main): If -c, emit second set of tests for -std=c++14 vs. -std=c++17
testing.
* g++.dg/compat/struct-layout-1_x1.h (empty_base): New type.
(EMPTY_BASE): Define.
(TX): Use EMPTY_BASE.
* g++.dg/compat/struct-layout-1_y1.h (empty_base): New type.
(EMPTY_BASE): Define.
(TX): Use EMPTY_BASE.

gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/compat/struct-layout-1.exp
gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c
gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h
gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h

index f3a3b69d155519db433fd2f4d45f6856f2b84afc..2d5b81f7d4c1971fb38822cd70b4a69878cb09e1 100644 (file)
@@ -1,5 +1,25 @@
 2020-04-21  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/94383
+       * g++.dg/compat/struct-layout-1.exp: If !$use_alt, add -c to generator
+       args.
+       * g++.dg/compat/struct-layout-1_generate.c (dg_options): Add another
+       %s to the start of dg-options arg.
+       (cxx14_vs_cxx17, do_cxx14_vs_cxx17): New variables.
+       (switchfiles): If cxx14_vs_cxx17, prepend -std=c++14 -DCXX14_VS_CXX17
+       or -std=c++17 -DCXX17_VS_CXX14 - randomly - to dg-options.
+       (output): Don't append further fields once one with flexible array
+       member is added.
+       (generate_random_tests): Don't use toplevel unions if cxx14_vs_cxx17.
+       (main): If -c, emit second set of tests for -std=c++14 vs. -std=c++17
+       testing.
+       * g++.dg/compat/struct-layout-1_x1.h (empty_base): New type.
+       (EMPTY_BASE): Define.
+       (TX): Use EMPTY_BASE.
+       * g++.dg/compat/struct-layout-1_y1.h (empty_base): New type.
+       (EMPTY_BASE): Define.
+       (TX): Use EMPTY_BASE.
+
        PR c/94641
        * c-c++-common/ubsan/pr94641.c: New test.
 
index fbfdd222f43100f4143c517d6f9b1ac383931679..99bfdbe2ff73dc46a8affb2a1cf6290ac9355e2f 100644 (file)
@@ -142,6 +142,9 @@ if { $status == 0 } then {
     file delete -force $tstobjdir
     file mkdir $tstobjdir
     set generator_args "-s $srcdir/$subdir -d $tstobjdir"
+    if { $use_alt == 0 } then {
+       set generator_args "$generator_args -c"
+    }
     if [info exists env(RUN_ALL_COMPAT_TESTS) ] then {
        set generator_args "$generator_args -n 15000"
     }
index 8b620e46da82ee679059b77a2b397ef39123492d..990e6f439e5db4098eb265b99c8ddc33c979526a 100644 (file)
@@ -1,5 +1,5 @@
 /* Structure layout test generator.
-   Copyright (C) 2004-2014
+   Copyright (C) 2004-2020
    Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>.
 
@@ -44,12 +44,12 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 const char *dg_options[] = {
-"/* { dg-options \"%s-I%s -Wno-abi\" } */\n",
-"/* { dg-options \"%s-I%s -mno-mmx -Wno-abi\" { target i?86-*-* x86_64-*-* } } */\n",
-"/* { dg-options \"%s-I%s -fno-common\" { target hppa*-*-hpux* powerpc*-*-darwin* *-*-mingw32* *-*-cygwin* } } */\n",
-"/* { dg-options \"%s-I%s -mno-mmx -fno-common -Wno-abi\" { target i?86-*-darwin* x86_64-*-darwin* i?86-*-mingw32* x86_64-*-mingw32* i?86-*-cygwin* } } */\n",
-"/* { dg-options \"%s-I%s -mno-base-addresses\" { target mmix-*-* } } */\n",
-"/* { dg-options \"%s-I%s -mlongcalls -mtext-section-literals\" { target xtensa*-*-* } } */\n"
+"/* { dg-options \"%s%s-I%s -Wno-abi\" } */\n",
+"/* { dg-options \"%s%s-I%s -mno-mmx -Wno-abi\" { target i?86-*-* x86_64-*-* } } */\n",
+"/* { dg-options \"%s%s-I%s -fno-common\" { target hppa*-*-hpux* powerpc*-*-darwin* *-*-mingw32* *-*-cygwin* } } */\n",
+"/* { dg-options \"%s%s-I%s -mno-mmx -fno-common -Wno-abi\" { target i?86-*-darwin* x86_64-*-darwin* i?86-*-mingw32* x86_64-*-mingw32* i?86-*-cygwin* } } */\n",
+"/* { dg-options \"%s%s-I%s -mno-base-addresses\" { target mmix-*-* } } */\n",
+"/* { dg-options \"%s%s-I%s -mlongcalls -mtext-section-literals\" { target xtensa*-*-* } } */\n"
 #define NDG_OPTIONS (sizeof (dg_options) / sizeof (dg_options[0]))
 };
 
@@ -508,6 +508,8 @@ static int short_enums;
 static const char *destdir;
 static const char *srcdir;
 static const char *srcdir_safe;
+static int cxx14_vs_cxx17;
+static int do_cxx14_vs_cxx17;
 FILE *outfile;
 
 void
@@ -516,6 +518,8 @@ switchfiles (int fields)
   static int filecnt;
   static char *destbuf, *destptr;
   int i;
+  int cxx14_first = 0;
+  const char *cxxnn = "";
 
   ++filecnt;
   if (outfile)
@@ -545,8 +549,15 @@ switchfiles (int fields)
       exit (1);
     }
 
+  if (cxx14_vs_cxx17)
+    {
+      cxx14_first = generate_random () & 1;
+      cxxnn = (cxx14_first
+              ? "-std=c++14 -DCXX14_VS_CXX17 "
+              : "-std=c++17 -DCXX14_VS_CXX17 ");
+    }
   for (i = 0; i < NDG_OPTIONS; i++)
-    fprintf (outfile, dg_options[i], "", srcdir_safe);
+    fprintf (outfile, dg_options[i], "", "", srcdir_safe);
   fprintf (outfile, "\n\
 #include \"struct-layout-1.h\"\n\
 \n\
@@ -572,7 +583,7 @@ int main (void)\n\
   if (outfile == NULL)
     goto fail;
   for (i = 0; i < NDG_OPTIONS; i++)
-    fprintf (outfile, dg_options[i], "-w ", srcdir_safe);
+    fprintf (outfile, dg_options[i], cxxnn, "-w ", srcdir_safe);
   fprintf (outfile, "\n\
 #include \"struct-layout-1_x1.h\"\n\
 #include \"t%03d_test.h\"\n\
@@ -583,8 +594,12 @@ int main (void)\n\
   outfile = fopen (destbuf, "w");
   if (outfile == NULL)
     goto fail;
+  if (cxx14_vs_cxx17)
+    cxxnn = (cxx14_first
+            ? "-std=c++17 -DCXX14_VS_CXX17 "
+            : "-std=c++14 -DCXX14_VS_CXX17 ");
   for (i = 0; i < NDG_OPTIONS; i++)
-    fprintf (outfile, dg_options[i], "-w ", srcdir_safe);
+    fprintf (outfile, dg_options[i], cxxnn, "-w ", srcdir_safe);
   fprintf (outfile, "\n\
 #include \"struct-layout-1_y1.h\"\n\
 #include \"t%03d_test.h\"\n\
@@ -1167,7 +1182,7 @@ e_insert (struct entry *e)
 void
 output (struct entry *e)
 {
-  int i;
+  int i, flex, len;
   char c;
   struct entry *n;
 
@@ -1190,9 +1205,17 @@ output (struct entry *e)
     fprintf (outfile, "U(%d,", idx);
   c = 'a';
 
-  int flex = 0;
+  flex = 0;
+  len = e[0].len;
   for (i = 1; i <= e[0].len; )
-    i += subfield (e + i, &c, &flex, 0);
+    {
+      if (flex)
+       {
+         e[0].len = i - 1;
+         break;
+       }
+      i += subfield (e + i, &c, &flex, 0);
+    }
   
   fputs (",", outfile);
   c = 'a';
@@ -1202,6 +1225,7 @@ output (struct entry *e)
       if (e[0].etype == ETYPE_UNION)
        break;
     }
+  e[0].len = len;
   fputs (")\n", outfile);
   if (output_one && idx == limidx)
     exit (0);
@@ -1539,7 +1563,7 @@ generate_random_tests (enum FEATURE features, int len)
     abort ();
   memset (e, 0, sizeof (e));
   r = generate_random ();
-  if ((r & 7) == 0)
+  if ((r & 7) == 0 && !cxx14_vs_cxx17)
     e[0].etype = ETYPE_UNION;
   else
     e[0].etype = ETYPE_STRUCT;
@@ -1577,7 +1601,7 @@ main (int argc, char **argv)
       if (argv[i][0] == '-' && argv[i][2] == '\0')
        c = argv[i][1];
       optarg = argv[i + 1];
-      if (!optarg)
+      if (!optarg && c != 'e' && c != 'c')
        goto usage;
       switch (c)
        {
@@ -1598,6 +1622,10 @@ main (int argc, char **argv)
          short_enums = 1;
          i--;
          break;
+       case 'c':
+         do_cxx14_vs_cxx17 = 1;
+         i--;
+         break;
        default:
          fprintf (stderr, "unrecognized option %s\n", argv[i]);
          goto usage;
@@ -1614,13 +1642,18 @@ main (int argc, char **argv)
          return 1;
        }
       n = limidx + 1;
+      if (do_cxx14_vs_cxx17)
+       {
+         fputs ("-c is incompatible with -i", stderr);
+         return 1;
+       }
     }
 
   if (destdir == NULL && !output_one)
     {
     usage:
       fprintf (stderr, "Usage:\n\
-%s [-e] [-s srcdir -d destdir] [-n count] [-i idx]\n\
+%s [-e] [-c] [-s srcdir -d destdir] [-n count] [-i idx]\n\
 Either -s srcdir -d destdir or -i idx must be used\n", argv[0]);
       return 1;
     }
@@ -1650,6 +1683,7 @@ Either -s srcdir -d destdir or -i idx must be used\n", argv[0]);
   for (i = 0; i < NATYPES2; ++i)
     if (attrib_types[i].bitfld)
       aligned_bitfld_types[n_aligned_bitfld_types++] = attrib_types[i];
+repeat:;
   for (i = 0; i < sizeof (features) / sizeof (features[0]); ++i)
     {
       int startidx = idx;
@@ -1696,6 +1730,14 @@ Either -s srcdir -d destdir or -i idx must be used\n", argv[0]);
     limidx = idx;
   while (idx < n)
     generate_random_tests (ALL_FEATURES, 1 + (generate_random () % 25));
+  if (do_cxx14_vs_cxx17)
+    {
+      cxx14_vs_cxx17 = 1;
+      do_cxx14_vs_cxx17 = 0;
+      limidx = 0;
+      idx = 0;
+      goto repeat;
+    }
   fclose (outfile);
   return 0;
 }
index e14433e0326f843448240fe9e938ea9b83622dbb..0023e475e8596e3ba3ab959c40ac76b4a41563ab 100644 (file)
@@ -35,8 +35,14 @@ int fn9 (void) { return 9; }
   s##n.x = v;                                                  \
   a##n[2].x = w;                                               \
   ++j;
+#ifdef CXX14_VS_CXX17
+struct empty_base {};
+#define EMPTY_BASE : public empty_base
+#else
+#define EMPTY_BASE
+#endif
 #define TX(n, type, attrs, fields, ops)                        \
-type S##n { fields } attrs;                                    \
+type S##n EMPTY_BASE { fields } attrs;                         \
 type S##n s##n;                                                        \
 extern type S##n a##n[5];                                      \
 extern type S##n check##n (type S##n, type S##n *,             \
index 9a5d2468a6ae78351505f97c1875c9839ff84430..a0bbccd25ceef5cade9e4f1f88f02b0102fed41e 100644 (file)
     FAIL (n, 56);                                              \
   ret.x = s##n.x;                                              \
   ++j;
+#ifdef CXX14_VS_CXX17
+struct empty_base {};
+#define EMPTY_BASE : public empty_base
+#else
+#define EMPTY_BASE
+#endif
 #define TX(n, type, attrs, fields, ops)                        \
-type S##n { fields } attrs;                                    \
+type S##n EMPTY_BASE { fields } attrs;                         \
 extern type S##n s##n;                                         \
 type S##n a##n[5];                                             \
 type S##n                                                      \