When can the C++ compiler devirtualize a call?

· coding · Source ↗

TLDR

  • Modern C++ compilers reliably devirtualize calls to final methods but diverge significantly on corner cases involving dataflow, internal linkage, and type provenance.

Key Takeaways

  • final class or method is the most portable devirtualization trigger; GCC, Clang, and MSVC all handle it, but ICC 21.1.9 misses inherited final methods.
  • Dataflow-based devirtualization degrades fast: Clang fails on conditional casts, MSVC and ICC fail even on simple Base *p = &d patterns.
  • Classes in anonymous namespaces grant internal linkage, blocking external derivation; compilers can devirtualize calls through such types within the same TU.
  • GCC uniquely detects devirtualization via incomplete external types whose members have internal linkage; no other tested compiler does this.
  • LTO whole-program analysis is explicitly out of scope; all results reflect single-TU compiler analysis only.

Hacker News Comment Review

  • One commenter frames devirtualization as fundamentally a whole-program problem, arguing separate compilation and the Itanium ABI leave single-TU compilers structurally limited without final or stack-provenance tricks.
  • Discussion is sparse with no substantive rebuttal or additional benchmark data surfaced.

Original | Discuss on HN