https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128652

            Bug ID: 128652
           Summary: [meta-bug] Inconsistent early/late debug info with LTO
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: luolongjuna at gmail dot com
  Target Milestone: ---

While revising the PR126348 patch after the v4 review
(https://gcc.gnu.org/pipermail/gcc-patches/2026-October/734019.html) and
auditing the remaining mismatches noted there, several distinct late-DWARF
issues turned up. This meta-bug groups them so each mechanism can be tracked
and addressed separately. In GDB, they show up as duplicated parameters and
local variables, local statics missing from 'info locals' / MI variable lists,
and inlined calls without a frame of their own (DW_TAG_inlined_subroutine
emitted without DW_AT_abstract_origin).

Early DWARF already records the source-level declarations and lexical scopes
for each input TU before IPA. Late DWARF annotates concrete instances and
refers back to those early DIEs via DW_AT_abstract_origin, but free_lang_data,
symbol resolution, WPA tree merging and scope pruning can redirect or drop the
tree links used to look them up. Inputs compiled with -g0 have no early DIEs of
their own.

Tested on x86_64 GNU/Linux with GCC 17.0.0 (g:bd921def14a4), GDB 17.2 and
binutils 2.46.1.

1. Input sources and missing descriptions (multiple TUs)

These need at least two input TUs and concern which input describes a concrete
instance, including inputs compiled without full debug info:

- PR126348: SCC unification or prevailing-declaration replacement redirects an
existing instance's origin to another input, while its children retain their
original early DIE references. Cases cover split clones, nested LGEN inlining,
decl-state slot replacement and mixed -g1/-g inputs.

- PR128616: a merged COMDAT declaration retains one input's early DIE, while
the prevailing body and its children come from another. This affects the
out-of-line function (DECL_ORIGIN(fn) == fn) and copies inlined from that body
during LTRANS.

- PR128617: in mixed -g0/-g links, process_dref supplies a surviving -g0
declaration with a -g input's early DIE while concrete children carry no
origins, causing duplicate inheritance; or gen_inlined_subroutine_die emits a
code-bearing inline entry without DW_AT_abstract_origin.

- PR128622: differing per-TU options keep the function declarations distinct
while the function body and local static are selected from different inputs.
flush_limbo_die_list attaches the static's location-bearing DIE under a
rangeless subprogram stub outside the executing instance, omitting it from
'info locals' and MI variable lists.

2. Inheritance and lexical structure (single TU)

These reproduce in a single TU with -flto (and do not occur with -fno-lto):

- PR128619: a constructor/destructor instance refers to the C1/C2/D2 clone's
early DIE, which itself refers to the abstract C4/D4 DIE. GDB chases child
origins to C4/D4, fails parent matching against the immediate clone origin, and
inherits duplicate children; in GDB 17.2, 'info args' then looks each argument
up by name and hits the locationless inherited copy.

- PR124864: a function-local static has storage, but its location is not
available through the concrete scope it belongs to. Cases cover constructors,
nested lexical blocks in plain C, early-inlined functions and multiple concrete
instances.

- PR128621: stripping a typedef's TYPE_DECL allows LGEN scope cleanup to prune
an outer lexical block while its surviving child block retains an early origin
under the original parent, causing GDB to inherit a second copy of the child's
locals.

The starting points differ: free_lang_data removes non-automatic VAR_DECLs and
TYPE_DECLs from BLOCK_VARS, and clears function abstract origins referring to
methods; BLOCK_NONLOCALIZED_VARS of early-inlined and cloned blocks are not
streamed; and for out-of-line clones, maybe_create_die_with_external_ref
introduces an extra origin hop by referring to the clone's own early DIE.

PR128622 bridges the two groups: its missing-static symptom matches the
early-inlined case of PR124864, while matching the per-TU options lets the
function declarations merge and turns the testcase into PR128616 without
changing which object supplies the body or static storage.

3. Related middle-end finding: per-function option sharing

- PR128623: cl_optimization_hash and cl_optimization_option_eq ignore
PerFunction flags not marked Optimization (such as -fvar-tracking), so
functions with conflicting var-tracking settings share one OPTIMIZATION_NODE,
making definition order (or LTO link order with mixed -g0/-g inputs) decide
whether variable tracking runs. Tracked via See Also as it also reproduces
without LTO.

Reduced reproducers, GDB output and the relevant DWARF relationships are in the
individual PRs. The upcoming v5 series for PR126348 addresses the v4 review and
preserves instances' input origins across SCC unification and
prevailing-declaration replacement; building on that, I plan a follow-up RFC on
the remaining cases.
  • [Bug debug/128652] New: [meta-bu... luolongjuna at gmail dot com via Gcc-bugs

Reply via email to