Skip to content

Human-Readable Symbol Names#138

Draft
cds-amal wants to merge 11 commits intomasterfrom
cds/unmangle
Draft

Human-Readable Symbol Names#138
cds-amal wants to merge 11 commits intomasterfrom
cds/unmangle

Conversation

@cds-amal
Copy link
Collaborator

@cds-amal cds-amal commented Mar 5, 2026

Dirty Deeds Demangled Dirt Cheap

So, this PR does one main thing: it makes the external function nodes in dot/d2 graphs actually readable. Those red boxes have always shown raw mangled symbols (_ZN4core3fmt3num3imp52_$LT$impl...), which is not exactly pleasant reading. Turns out rustc_demangle is already sitting right there in the sysroot; we just weren't using it.

The new flag is UNMANGLE=1, surfaced through Make:

make svg UNMANGLE=1

It composes with the SKIPLANGSTART=1 flag (also wired through Make in this PR):

make svg UNMANGLE=1 SKIPLANGSTART=1

A natural question: does demangling affect graph structure? Turns out, no. Display names are strictly separated from node identity. ctx.functions stays mangled (preserving hash-based node IDs), so mangled and unmangled graphs are structurally identical; only labels differ. The GraphContext gains a display_names map that holds demangled names when the flag is set, and renderers call display_name() to get the label for a given node.

A few other things came along for the ride:

  • rustc_demangle added to the compat layer (it's already available in the sysroot, so this is not a new dependency; just a new extern crate)
  • External function nodes sorted before emission for deterministic dot output (previously HashMap iteration order was causing non-deterministic layouts across runs)
  • Both flags wired through a single GRAPH_ENV variable in the Makefile
  • Fixed double-escaping of \n line separators in D2 container labels (escape_d2 was turning \n into \\n; swapped call order so escaping happens before line-breaking)
  • README updated

Depends on #119 (dc/remove-lang-start): the ItemFilter enum and SKIP_LANG_START support that this branch stacks on.

Before

assert_eq

assert_eq smir

After

assert_eq

assert_eq smir

Test plan

  • make integration-test passes (no change to JSON output)
  • make test-skip-lang-start passes
  • make dot and make dot UNMANGLE=1 produce structurally identical dot files (same node IDs, same edges; different labels only)
  • make svg UNMANGLE=1 SKIPLANGSTART=1 produces readable, lang_start-free SVGs
  • Visual inspection: red external function nodes show core::panicking::panic::h... instead of _ZN4core9panicking5panic17h...

dkcumming and others added 9 commits March 4, 2026 23:22
This filters out all `lang_start` items (functions, closures, drop glue
etc.). It only removes the items if they are `std::rt::lang_start` or
are exclusively reachable by those functions. That means `black_box` is
removed if it is not called otherwise in the program, but if it is then
it is not removed. There is a couple of stages to get the data together
in the right form so that only the items desired to be removed are.
Introduces an extensible ItemFilter enum so future exclusion predicates
can be added by just adding a variant, wiring its env var in enabled(),
and implementing compute_exclusions.

The key behavioral change: apply_all() now prunes ctx.functions in
addition to items, so ctx.resolve_call_target() returns None for
excluded callees. This eliminates the need to thread an `excluded` set
through every render function; both dot and d2 renderers are simplified.
Adds a `make test-skip-lang-start` target that runs every test program
through the D2 renderer with SKIP_LANG_START=1 and verifies the output
contains no lang_start references. Catches regressions in the ItemFilter
pipeline without needing separate golden files.
…ring

Replace if-let + early-return with match expression in filter_map,
use matches! macro for single-arm boolean match, and switch enabled()
from imperative push to declarative array-of-options pattern.
The integration test now validates at the data-structure level instead
of grepping rendered output. When ASSERT_FILTER=1 is set alongside
SKIP_LANG_START=1, apply_all() asserts two things:

1. The filter's exclusion set is non-empty (precondition: lang_start
   items were present to begin with).
2. No matching items survive in the filtered output (postcondition:
   the filter actually worked).

The precondition check is pedantically complete: std::rt::lang_start is
the runtime wrapper rustc generates for every crate with a fn main, so
it will always appear in monomorphized output. Every one of the 29 test
programs has a main function and every expected output contains exactly
11 lang_start references. It would take a fundamental change to rustc's
runtime initialization for this to stop being true; but if it does, the
assertion will tell us the test data is stale rather than silently
passing.

The more realistic failure mode: someone adds a library crate (no main)
to the test suite. The assert message spells this out and gives two
actionable options (skip lib crates in the test target, or gate the
filter on the presence of main).
echo's treatment of \n is shell-dependent (bash interprets it by
default, zsh and POSIX sh do not without -e). Switch report() and
the failure summary to printf in both integration-test and
test-skip-lang-start targets.
@cds-amal cds-amal changed the title Cds/unmangle Dirty Names Demangled Dirt Cheap Mar 5, 2026
@cds-amal cds-amal changed the title Dirty Names Demangled Dirt Cheap Dirty Deeds Demangled Dirt Cheap Mar 7, 2026
@cds-amal cds-amal changed the title Dirty Deeds Demangled Dirt Cheap Dirty Deeds Demangled Dirt Cheap – Human-Readable Symbol Names Mar 8, 2026
@cds-amal cds-amal changed the title Dirty Deeds Demangled Dirt Cheap – Human-Readable Symbol Names Human-Readable Symbol Names Mar 8, 2026
Add GRAPH_UNMANGLE support to demangle symbol names in dot/d2 output,
separate display names from node identity so demangled names render
correctly, sort external function nodes for deterministic output, fix
double-escaping of newlines in D2 container labels, and wire UNMANGLE
and SKIPLANGSTART env vars through Make graph targets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants