From 619602346aed9dae3f338d9f18767414446adf78 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 21 Apr 2020 17:08:10 +0200 Subject: [PATCH] testsuite: Extend C++ struct-layout-1.exp testing to test C++14 vs. C++17 interoperability of structs with empty bases [PR94383] 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 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 | 20 +++++ .../g++.dg/compat/struct-layout-1.exp | 3 + .../g++.dg/compat/struct-layout-1_generate.c | 74 +++++++++++++++---- .../g++.dg/compat/struct-layout-1_x1.h | 8 +- .../g++.dg/compat/struct-layout-1_y1.h | 8 +- 5 files changed, 95 insertions(+), 18 deletions(-) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f3a3b69d155..2d5b81f7d4c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,25 @@ 2020-04-21 Jakub Jelinek + 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. diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1.exp b/gcc/testsuite/g++.dg/compat/struct-layout-1.exp index fbfdd222f43..99bfdbe2ff7 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1.exp +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1.exp @@ -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" } diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c index 8b620e46da8..990e6f439e5 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c @@ -1,5 +1,5 @@ /* Structure layout test generator. - Copyright (C) 2004-2014 + Copyright (C) 2004-2020 Free Software Foundation, Inc. Contributed by Jakub Jelinek . @@ -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; } diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h b/gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h index e14433e0326..0023e475e85 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_x1.h @@ -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 *, \ diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h b/gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h index 9a5d2468a6a..a0bbccd25ce 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_y1.h @@ -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 \ -- 2.30.2