On Thu, 23 Jul 2026, Longjun Luo wrote:
> 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.
I prefer the global removal, but I CCed Eric in case he remembers
details and can argue the actual issue still exists.
Thanks,
Richard.
> 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)
> >
>
--
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)