Joseph Myers <[email protected]> writes:
> Bug 117164 is an ICE on an existing test with -std=gnu23 involving a
> nested function returning a variable-size structure (and I think the
> last bug needing to be resolved before switching to -std=gnu23 as the
> default, as without fixing this would be a clear regression from a
> change in default).
>
> The problem is a GIMPLE verification failure where (after type
> remapping from inlining / cloning) the return type of the function no
> longer exactly matches the type to which it is assigned (these types
> use structural equality, which means GIMPLE verification can't use
> TYPE_CANONICAL and expects an exact match). Specifically, the nested
> function itself is *not* inlined (the -fno-inline-small-functions in
> the original test nested-func-12.c, I think, or the noinline attribute
> in some of my variant tests), but the function containing it is either
> cloned (the --param ipa-cp-eval-threshold=0 in the original test) or
> inlined. (I'm not sure what role -fno-guess-branch-probability plays
> in getting the right situation for the ICE; maybe affecting when
> inlining or cloning is considered profitable?)
>
> There is in fact existing code in tree-nested.cc to prevent inlining
> of a function containing a nested function with variably modified
> *argument* types. I think the same issue of ensuring consistency of
> types means such prevention should also apply for a variably modified
> return type. Furthermore, exactly the same problem applies for
> cloning for other reasons as it does for inlining. Thus, change the
> logic to include variably modified return types for nested functions
> alongside those for arguments of those functions as a reason not to
> inline, and also add the noclone attribute in these cases.
>
> Bootstrapped with no regressions for x86-64-pc-linux-gnu.
>
> PR c/117164
>
> gcc/
> * tree-nested.cc: Include "attribs.h".
> (check_for_nested_with_variably_modified): Also return true for
> variably modified return type.
> (create_nesting_tree): If check_for_nested_with_variably_modified
> returns true, also add noclone attribute.
>
> gcc/testsuite/
> * gcc.dg/nested-func-13.c, gcc.dg/nested-func-14.c:
> gcc.dg/nested-func-15.c, gcc.dg/nested-func-16.c,
> gcc.dg/nested-func-17.c: New tests.
>
> diff --git a/gcc/testsuite/gcc.dg/nested-func-13.c
> b/gcc/testsuite/gcc.dg/nested-func-13.c
> new file mode 100644
> index 000000000000..697a62354109
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-13.c
> @@ -0,0 +1,6 @@
> +/* Test nested-func-12.c with -std=gnu17. */
> +/* { dg-do run } */
> +/* { dg-options "-Ofast --param ipa-cp-eval-threshold=0
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu17" } */
> +/* { dg-require-effective-target alloca } */
> +
> +#include "nested-func-12.c"
> diff --git a/gcc/testsuite/gcc.dg/nested-func-14.c
> b/gcc/testsuite/gcc.dg/nested-func-14.c
> new file mode 100644
> index 000000000000..05a77bdb1a5a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-14.c
> @@ -0,0 +1,6 @@
> +/* Test nested-func-12.c with -std=gnu23. */
> +/* { dg-do run } */
> +/* { dg-options "-Ofast --param ipa-cp-eval-threshold=0
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +#include "nested-func-12.c"
> diff --git a/gcc/testsuite/gcc.dg/nested-func-15.c
> b/gcc/testsuite/gcc.dg/nested-func-15.c
> new file mode 100644
> index 000000000000..490d69599868
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-15.c
> @@ -0,0 +1,29 @@
> +/* Bug 117164: ICE with -std=gnu23 inlining function containing call
> + to non-inlined nested function returning variable-size struct. */
> +/* { dg-do run } */
nested-func-12 which exposed the problem, as reported in PR117164, has
assertions on the value of a. This test doesn't, so its value as a
runtime test is questionable as-is.
> +/* { dg-options "-O3 --param ipa-cp-eval-threshold=0
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +void
> +foo (int n)
> +{
> + struct S { int a[n]; };
> +
> + struct S
> + fn (void)
> + {
> + struct S s;
> + s.a[0] = 42;
> + return s;
> + }
> +
> + fn ();
> + fn ();
> + fn ();
> +}
> +
> +int
> +main (void)
> +{
> + foo (1);
> +}
>
> [...]
thanks,
sam