Message ID | 20200421095702.GY2424@tucnak |
---|---|
State | New |
Headers | show |
Series | testsuite: Extend C++ struct-layout-1.exp testing to test C++14 vs. C++17 interoperability of structs with empty bases [PR94383] | expand |
On 4/21/20 5:57 AM, Jakub Jelinek wrote: > Hi! > > 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. > > Ok for trunk? OK. > 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/g++.dg/compat/struct-layout-1.exp.jj 2020-01-12 11:54:37.044403889 +0100 > +++ gcc/testsuite/g++.dg/compat/struct-layout-1.exp 2020-04-20 19:00:54.956968103 +0200 > @@ -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" > } > --- gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c.jj 2020-01-12 11:54:37.045403874 +0100 > +++ gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c 2020-04-20 20:00:35.428544841 +0200 > @@ -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. > #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 feat > 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 mu > 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 mu > 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; > } > --- gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h.jj 2020-01-11 16:31:54.558300646 +0100 > +++ gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h 2020-04-20 18:59:10.307557481 +0200 > @@ -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 *, \ > --- gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h.jj 2020-01-11 16:31:54.558300646 +0100 > +++ gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h 2020-04-20 18:59:51.045938756 +0200 > @@ -37,8 +37,14 @@ > 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 \ > > > Jakub >
--- gcc/testsuite/g++.dg/compat/struct-layout-1.exp.jj 2020-01-12 11:54:37.044403889 +0100 +++ gcc/testsuite/g++.dg/compat/struct-layout-1.exp 2020-04-20 19:00:54.956968103 +0200 @@ -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" } --- gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c.jj 2020-01-12 11:54:37.045403874 +0100 +++ gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c 2020-04-20 20:00:35.428544841 +0200 @@ -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. #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 feat 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 mu 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 mu 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; } --- gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h.jj 2020-01-11 16:31:54.558300646 +0100 +++ gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h 2020-04-20 18:59:10.307557481 +0200 @@ -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 *, \ --- gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h.jj 2020-01-11 16:31:54.558300646 +0100 +++ gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h 2020-04-20 18:59:51.045938756 +0200 @@ -37,8 +37,14 @@ 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 \