Case 86: Tag struct renamed (empty class re-mangling)¶
| Field | Value |
|---|---|
| Verdict | π΄ BREAKING |
| Category | Breaking |
| Platforms | Linux, macOS, Windows |
| Flags | ABI break, API break |
Detected ChangeKinds |
tag_type_renamed |
| Source files | browse on GitHub |
Category: Mangling ABI | Verdict: BREAKING
What breaks¶
Empty tag structs are the workhorses of C++ template specialization:
The library ships explicit instantiations that bake the tag's mangled name into symbol names:
v2 renames brute_force β search_brute. Mechanically:
- The struct has zero fields and zero methods. Layout-based detectors
(
type_size_changed,type_field_*) see nothing. - The old type appears as
TYPE_REMOVED, the new one asTYPE_ADDEDβ an existing detector can produce both findings but does not link them. - Every explicit instantiation referencing the old tag gets a brand-new mangled name. Consumer binaries linked against v1 request the old symbol at load time and get an unresolved-symbol error.
Why this is its own ChangeKind¶
Renaming a non-empty class is rare and would already trigger many
layout-related findings. Renaming a tag struct β the only purpose of
which is to participate in mangling β is uniquely a oneDAL/Boost/std-style
risk, and no existing ChangeKind correlates the disappearance with the
appearance. A new TAG_TYPE_RENAMED makes the correlation explicit.
How abicheck detects it¶
The new detector (abicheck/diff_onedal.py::detect_tag_type_renamed) runs after the
type-diff pass:
- Find every
TYPE_REMOVEDfor a record type with zero fields and no virtual methods (an "empty" type). - Find every
TYPE_ADDEDfor an empty record type in the same parent namespace. - Look for a symbol-rename pair in the symbol diff where the old mangled substring contains the removed tag's name segment and the new mangled substring contains the added tag's name segment.
- When both halves match, emit a single
TAG_TYPE_RENAMEDfinding pairing the two and suppress the redundantTYPE_REMOVED/TYPE_ADDED.
Real-world reference¶
oneDAL's cpp/oneapi/dal/algo/*/common.hpp defines:
namespace method { struct by_default {}; struct brute_force {}; struct kd_tree {}; }
namespace task { struct by_default {}; struct classification {}; struct regression {}; }
β¦and every descriptor<Float, Method, Task> instantiation embeds these
tags in its mangled name. Renaming any of them silently breaks every
shipped instantiation symbol.
Source files¶
See also: Examples overview Β· All BREAKING cases Β· Category: Breaking.