Thanks. I traced the setting back to PR middle-end/87574.

r264943 removed the previously unconditional DECL_IGNORED_P setting from
expand_thunk, which exposed the DWARF ICE reported as PR87574. r265028
(Eric Botcazou) then restored it conditionally for forced GIMPLE thunks.

For the record, the PR87574 reproducer itself is not LTO-related: it is a
plain "-O2 -g" ICE in add_data_member_location_attribute
(dwarf2out.c:19226), and its testcase g++.dg/other/pr87574.C is a
{ dg-do compile }, so compiling it exercises the original failure mode
directly.

There are in fact three callers of
expand_thunk (..., /*force_gimple_thunk=*/true): inline_call
(ipa-inline-transform.cc), the ICF wrapper
(cgraph_node::create_wrapper), and coverage instrumentation
(tree-profile.cc).

I built an x86_64-pc-linux-gnu compiler from trunk commit 5453f858146
with only the conditional DECL_IGNORED_P setting removed, and ran these
targeted compile checks:

- g++.dg/other/pr87574.C compiled with -O2 -g and no ICE; an additional
IPA inline dump showed the thunk expanded through inline_call;
- the new PR126355 test source compiled with the test options; the ICF
dump showed that the wrapper was created, and the assembly showed an
address-bearing DIE for pr_icf_wrapper_b;
- g++.dg/tree-prof/devirt.C compiled to assembly with
-O3 -g -fprofile-generate -fno-profile-values
-fdump-ipa-cgraph-details -S -dA, and the generated thunks contained
their __gcov counters, exercising the tree-profile.cc path.

Thus, the original PR87574 failure no longer reproduces on this trunk
checkout with the setting removed, and g++.dg/other/pr87574.C remains as
a guard should it ever return.

Given that, removing the setting globally looks worth testing as the
simpler fix. It addresses the common setting in expand_thunk rather than
undoing it only in the ICF caller. It also changes debug emission for the
inline_call and coverage paths, however, so I will do a full bootstrap and
regtest, with particular attention to the LTO, debug, guality, dwarf2, and
tree-prof suites, before posting such a revision.

Would you prefer that global removal, or the more conservative
caller-specific patch as posted? I can go either way; the ICF-only version
remains a fallback if the removal turns up any fallout.

Richard Biener <[email protected]> 于2026年7月23日周四 16:38写道:

> On Thu, 23 Jul 2026, Longjun Luo wrote:
>
> > When IPA ICF keeps a distinct symbol for an address-taken function by
> > replacing its body with a wrapper, cgraph_node::create_wrapper reuses the
> > original function declaration and its early debug DIE.
> >
> > create_wrapper then calls expand_thunk with force_gimple_thunk set.
> Forced
> > GIMPLE thunks are normally created after early debug, so expand_thunk
> marks
> > their declarations ignored.  For an ICF wrapper this also prevents final
> > debug emission from attaching the wrapper address to the existing DIE.
> > The wrapper consequently has code and an STT_FUNC symbol but no
> > address-bearing DW_TAG_subprogram DIE.
> >
> > Preserve the declaration's original DECL_IGNORED_P value across forced
> > GIMPLE thunk expansion in create_wrapper.  Declarations that were already
> > ignored remain ignored, while an original source declaration can receive
> > its final address information.
> >
> > Tested on x86_64-pc-linux-gnu with the new gcc.dg/debug/dwarf2 test.  The
> > test fails before the change and passes afterwards.
>
> There's two calls to expand_thunk (..., true), one from ICF as you
> figured and one from inline_call ().  I wonder if it's better to
> remove
>
>       /* We need to force DECL_IGNORED_P when the thunk is created
>          after early debug was run.  */
>       if (force_gimple_thunk)
>         DECL_IGNORED_P (thunk_fndecl) = 1;
>
> or figure why it was put there and see if the reason still holds
> (sounds LTO-ish).
>
> Richard.
>
> >       PR debug/126355
> >
> > gcc/ChangeLog:
> >
> >       * cgraphunit.cc (cgraph_node::create_wrapper): Preserve
> >       DECL_IGNORED_P across forced GIMPLE thunk expansion.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * gcc.dg/debug/dwarf2/pr126355.c: New test.
> >
> > Signed-off-by: Longjun Luo <[email protected]>
> > ---
> >  gcc/cgraphunit.cc                            |  5 +++
> >  gcc/testsuite/gcc.dg/debug/dwarf2/pr126355.c | 35 ++++++++++++++++++++
> >  2 files changed, 40 insertions(+)
> >  create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr126355.c
> >
> > diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
> > index 67aaebf108b..d397c9ae4cc 100644
> > --- a/gcc/cgraphunit.cc
> > +++ b/gcc/cgraphunit.cc
> > @@ -2683,7 +2683,12 @@ cgraph_node::create_wrapper (cgraph_node *target)
> >        arguments = TREE_CHAIN (arguments);
> >      }
> >
> > +  /* Forced GIMPLE thunks are normally ignored because they are created
> > +     after early debug.  ICF wrappers retain the original function decl
> and
> > +     its early DIE, so preserve its original debug state.  */
> > +  bool ignored_p = DECL_IGNORED_P (decl);
> >    expand_thunk (this, false, true);
> > +  DECL_IGNORED_P (decl) = ignored_p;
> >    thunk_info::remove (this);
> >
> >    /* Inline summary set-up.  */
> > diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr126355.c
> b/gcc/testsuite/gcc.dg/debug/dwarf2/pr126355.c
> > new file mode 100644
> > index 00000000000..35e321008aa
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr126355.c
> > @@ -0,0 +1,35 @@
> > +/* PR debug/126355 */
> > +/* Verify that an IPA ICF wrapper for an address-taken function keeps an
> > +   address-bearing subprogram DIE.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -g -gdwarf -dA -fdump-ipa-icf-details" } */
> > +
> > +int
> > +pr_icf_wrapper_a (const char *host)
> > +{
> > +  (void) host;
> > +  return 0;
> > +}
> > +
> > +int
> > +pr_icf_wrapper_b (const char *host)
> > +{
> > +  (void) host;
> > +  return 0;
> > +}
> > +
> > +int (*keep_a) (const char *) = pr_icf_wrapper_a;
> > +int (*keep_b) (const char *) = pr_icf_wrapper_b;
> > +
> > +int
> > +main (int argc, char **argv)
> > +{
> > +  const char *arg = argc > 1 ? argv[1] : "x";
> > +  return keep_a (arg) + keep_b (arg);
> > +}
> > +
> > +/* Check the ICF direction explicitly because the DWARF scan below
> inspects
> > +   pr_icf_wrapper_b, the wrapper.  */
> > +/* { dg-final { scan-ipa-dump "Semantic equality
> hit:pr_icf_wrapper_a/\[0-9+\]+->pr_icf_wrapper_b/\[0-9+\]+" "icf" } } */
> > +/* { dg-final { scan-ipa-dump "Wrapper has been created" "icf" } } */
> > +/* { dg-final { scan-assembler "\\(DIE \\(0x\[0-9a-f\]+\\)
> DW_TAG_subprogram\\)\[\r\n\]+(\[^\r\n\]*\[\r\n\]+){1,12}\[^\r\n\]*DW_AT_name:
> \"pr_icf_wrapper_b\"\[\r\n\]+(\[^\r\n\]*\[\r\n\]+){1,12}\[^\r\n\]*DW_AT_low_pc"
> } } */
> >
>
> --
> Richard Biener <[email protected]>
> SUSE Software Solutions Germany GmbH,
> Frankenstrasse 146, 90461 Nuernberg, Germany;
> GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)
>

Reply via email to