Message ID | 20220106084808.GW2646553@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Ensure some more that immediate functions aren't gimplified [PR103912] | expand |
On 1/6/22 03:48, Jakub Jelinek wrote: > Hi! > > Immediate functions should never be emitted into assembly, the FE doesn't > genericize them and does various things to ensure they aren't gimplified. > But the following testcase ICEs anyway due to that, because the consteval > function returns a lambda, and operator() of the lambda has > decl_function_context of the consteval function. cgraphunit.c then > does: > /* Preserve a functions function context node. It will > later be needed to output debug info. */ > if (tree fn = decl_function_context (decl)) > { > cgraph_node *origin_node = cgraph_node::get_create (fn); > enqueue_node (origin_node); > } > which enqueues the immediate function and then tries to gimplify it, > which results in ICE because it hasn't been genericized. > > When I try similar testcase with constexpr instead of consteval and > static constinit auto instead of auto in main, what happens is that > the functions are gimplified, later ipa.c discovers they aren't reachable > and sets body_removed to true for them (and clears other flags) and we end > up with a debug info which has the foo and bar functions without > DW_AT_low_pc and other code specific attributes, just stuff from its BLOCK > structure and in there the lambda with DW_AT_low_pc etc. > > The following patch attempts to emulate that behavior early, so that cgraph > doesn't try to gimplify those and pretends they were already gimplified > and found unused and optimized away. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2022-01-06 Jakub Jelinek <jakub@redhat.com> > > PR c++/103912 > * semantics.c (expand_or_defer_fn): For immediate functions, set > node->body_removed to true and clear analyzed, definition and > force_output. > * decl2.c (c_parse_final_cleanups): Ignore immediate functions for > expand_or_defer_fn. > > * g++.dg/cpp2a/consteval26.C: New test. > > --- gcc/cp/semantics.c.jj 2022-01-03 10:40:48.000000000 +0100 > +++ gcc/cp/semantics.c 2022-01-05 12:52:11.484379138 +0100 > @@ -4785,6 +4785,18 @@ expand_or_defer_fn (tree fn) > emit_associated_thunks (fn); > > function_depth--; > + > + if (DECL_IMMEDIATE_FUNCTION_P (fn)) > + { > + cgraph_node *node = cgraph_node::get (fn); > + if (node) This can be if (cgraph_node *node = cgraph_node::get (fn)) OK either way. > + { > + node->body_removed = true; > + node->analyzed = false; > + node->definition = false; > + node->force_output = false; > + } > + } > } > } > > --- gcc/cp/decl2.c.jj 2022-01-03 10:40:48.083068010 +0100 > +++ gcc/cp/decl2.c 2022-01-05 12:53:34.930204119 +0100 > @@ -5272,6 +5272,7 @@ c_parse_final_cleanups (void) > if (!DECL_EXTERNAL (decl) > && decl_needed_p (decl) > && !TREE_ASM_WRITTEN (decl) > + && !DECL_IMMEDIATE_FUNCTION_P (decl) > && !node->definition) > { > /* We will output the function; no longer consider it in this > --- gcc/testsuite/g++.dg/cpp2a/consteval26.C.jj 2022-01-05 12:42:07.918878074 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/consteval26.C 2022-01-05 12:40:18.853416637 +0100 > @@ -0,0 +1,39 @@ > +// PR c++/103912 > +// { dg-do run { target c++20 } } > +// { dg-additional-options "-O2 -g -fkeep-inline-functions" } > + > +extern "C" void abort (); > + > +struct A { A () {} }; > + > +consteval auto > +foo () > +{ > + if (1) > + ; > + return [] (A x) { return 1; }; > +} > + > +consteval auto > +bar (int a) > +{ > + int b = a + 4; > + if (1) > + ; > + return [=] (A x) { return a + b; }; > +} > + > +int > +main () > +{ > + A x; > + auto h = foo (); > + if (h (x) != 1) > + abort (); > + auto i = bar (5); > + if (i (x) != 14) > + abort (); > + auto j = bar (42); > + if (j (x) != 88) > + abort (); > +} > > Jakub >
--- gcc/cp/semantics.c.jj 2022-01-03 10:40:48.000000000 +0100 +++ gcc/cp/semantics.c 2022-01-05 12:52:11.484379138 +0100 @@ -4785,6 +4785,18 @@ expand_or_defer_fn (tree fn) emit_associated_thunks (fn); function_depth--; + + if (DECL_IMMEDIATE_FUNCTION_P (fn)) + { + cgraph_node *node = cgraph_node::get (fn); + if (node) + { + node->body_removed = true; + node->analyzed = false; + node->definition = false; + node->force_output = false; + } + } } } --- gcc/cp/decl2.c.jj 2022-01-03 10:40:48.083068010 +0100 +++ gcc/cp/decl2.c 2022-01-05 12:53:34.930204119 +0100 @@ -5272,6 +5272,7 @@ c_parse_final_cleanups (void) if (!DECL_EXTERNAL (decl) && decl_needed_p (decl) && !TREE_ASM_WRITTEN (decl) + && !DECL_IMMEDIATE_FUNCTION_P (decl) && !node->definition) { /* We will output the function; no longer consider it in this --- gcc/testsuite/g++.dg/cpp2a/consteval26.C.jj 2022-01-05 12:42:07.918878074 +0100 +++ gcc/testsuite/g++.dg/cpp2a/consteval26.C 2022-01-05 12:40:18.853416637 +0100 @@ -0,0 +1,39 @@ +// PR c++/103912 +// { dg-do run { target c++20 } } +// { dg-additional-options "-O2 -g -fkeep-inline-functions" } + +extern "C" void abort (); + +struct A { A () {} }; + +consteval auto +foo () +{ + if (1) + ; + return [] (A x) { return 1; }; +} + +consteval auto +bar (int a) +{ + int b = a + 4; + if (1) + ; + return [=] (A x) { return a + b; }; +} + +int +main () +{ + A x; + auto h = foo (); + if (h (x) != 1) + abort (); + auto i = bar (5); + if (i (x) != 14) + abort (); + auto j = bar (42); + if (j (x) != 88) + abort (); +}