← board

RTTI is emitted unconditionally (every class, even a classless program) — dead weight on ESP32/embedded

What we measured (frozen, -uPXX_MANAGED_STRING)

build file code data
bare begin end. x86-64 679 B 351 208
bare begin end. x86-64 --no-signals 407 B 79 208
bare begin end. xtensa/ESP ~168 B data 6 168

Breakdown of the x86-64 baseline growth vs the old ~280 B:

The two RTTI wastes

  1. Every user class gets a full RTTI header even when never reflected. Deliberate today — EmitRTTI (rtti_emit.inc ~319-338) emits one RTTI_CLS_SIZE header + interned name per class so ClassName answers for any class (the published-only gate used to make ClassName a coin flip). Correct, but on ESP32 with classes and no is/as/ClassName/TypeInfo/streaming it is pure size cost.
  2. A classless program still emits a TObject remnant (~8 B interned name). The "plain wrong" case: zero classes, zero reflection, yet RTTI bytes ship.

Goal

Opt OUT of RTTI to compress embedded size, keep it available (opt-in / on-demand) for debugging, reflection, and advanced software (streaming, fpcunit, dynamic dispatch).

Approaches (ranked)

  1. Usage-driven emission (north-star). Emit a class's RTTI only if the program actually reflects on it — ClassName/ClassType/InheritsFrom, is/as against it, TypeInfo, published-member access, LFM streaming. Track a per-class "RTTI-touched" bit during parse/lower; EmitRTTI skips untouched classes. Zero cost when unused, no flag, no silent breakage. Hard part: cases the compiler can't see statically (LFM FindClass-by-name, dynamic streaming) need a force-on escape.
  2. --rtti=auto|full|none flag (pragmatic first step). auto = usage-driven (or, interim, the current all-classes behavior); full forces every class (for dynamic/streaming reflection the compiler can't prove); none hard-off — a reflection op under none is a compile-time error, never a silent wrong value. ESP/bare default leans (auto, and skip the classless TObject remnant).
  3. Minimum quick win, independent of the above: when UClsCount = 0 and no reflection op appears, emit NO RTTI at all (drop the TObject remnant).

Guard rails

Not in scope (separate, minor)

Elevated 2026-07-20 — this IS the --rtti=none answer

[[decide-rtti-none-semantics]] resolved as option C: usage-driven emission, and no --rtti=none flag ships at all. So this ticket is no longer an optimization sitting alongside a user-facing switch — it is the entire mechanism by which RTTI shrinks, and the ESP/size-constrained audience has nothing else to reach for. Any remaining text describing --rtti=none as a planned switch is superseded.