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)