Skip to content

fix(bitflags): Prevent linker errors from multiple defined BitFlags<N>::s_bitNameList#2888

Merged
xezon merged 4 commits into
TheSuperHackers:mainfrom
xezon:xezon/fix-bitflags-names-conflicts-2
Jul 19, 2026
Merged

fix(bitflags): Prevent linker errors from multiple defined BitFlags<N>::s_bitNameList#2888
xezon merged 4 commits into
TheSuperHackers:mainfrom
xezon:xezon/fix-bitflags-names-conflicts-2

Conversation

@xezon

@xezon xezon commented Jul 18, 2026

Copy link
Copy Markdown

This change prevents linker errors from multiple defined BitFlags<N>::s_bitNameList by introducing a templated tag type.

@xezon xezon added Build Anything related to building, compiling Fix Is fixing something, but is not user facing labels Jul 18, 2026
@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents linker errors that would arise when two distinct BitFlags<N> typedefs share the same NUMBITS value, causing their s_bitNameList explicit template specializations to collide under the ODR. The fix adds a typename TAG phantom-type parameter to BitFlags, ensuring every typedef produces a distinct instantiation with its own s_bitNameList.

  • BitFlags.h (both Generals/ and GeneralsMD/) gains a second template parameter typename TAG; all method definitions in BitFlagsIO.h are updated to match.
  • Every typedef site (11 types across both trees plus three Core/ header files) now passes a uniquely-named tag struct (e.g., struct KindOfMaskTypeTag) as the second argument.
  • Existing .cpp definitions of s_bitNameList reference the type through their typedef names (e.g., KindOfMaskType::s_bitNameList), so they automatically resolve to the new, unique specializations without any .cpp changes.

Confidence Score: 5/5

Safe to merge — the change is purely additive (adds a phantom type parameter), all header-level usages have been updated, and the existing .cpp definitions of s_bitNameList continue to work via typedef names.

The phantom-type fix correctly differentiates all BitFlags instantiations. No old-style BitFlags calls remain in the codebase, the .cpp explicit specializations remain valid, and the functions that depend on s_bitNameList (parse, xfer, INI parsers) are all correctly updated.

No files require special attention.

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Include/Common/BitFlags.h Adds typename TAG as a second template parameter to BitFlags; TAG is unused within the class body (intentional phantom type for unique instantiation).
GeneralsMD/Code/GameEngine/Include/Common/BitFlags.h Mirror of Generals BitFlags.h change — same typename TAG addition, identical result.
Generals/Code/GameEngine/Include/Common/BitFlagsIO.h Updates all out-of-class template method definitions (parse, parseFromINI, parseSingleBitFromINI, xfer) to use BitFlags<NUMBITS, TAG> to match the new class signature.
GeneralsMD/Code/GameEngine/Include/Common/BitFlagsIO.h Mirror of Generals BitFlagsIO.h change — identical method signature updates.
Core/GameEngine/Include/Common/DynamicAudioEventInfo.h Member variable m_overriddenFields now uses BitFlags<OVERRIDE_COUNT, struct OverriddenTag>. OverriddenTag is forward-declared as a template argument inside the class body, injecting the name into the enclosing namespace — valid but slightly unusual compared to the file-scope tag declarations used elsewhere.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class BitFlags~NUMBITS, TAG~ {
        -bitset~NUMBITS~ m_bits
        +static s_bitNameList[]
        +parse(INI*, AsciiString*)
        +xfer(Xfer*)
        +parseFromINI(INI*, void*, void*, void*)
        +parseSingleBitFromINI(INI*, void*, void*, void*)
    }
    class KindOfMaskType {
        <<typedef BitFlags~KINDOF_COUNT, KindOfMaskTypeTag~>>
    }
    class DisabledMaskType {
        <<typedef BitFlags~DISABLED_COUNT, DisabledMaskTypeTag~>>
    }
    class ModelConditionFlags {
        <<typedef BitFlags~MODELCONDITION_COUNT, ModelConditionFlagsTag~>>
    }
    class UpgradeMaskType {
        <<typedef BitFlags~UPGRADE_MAX_COUNT, UpgradeMaskTypeTag~>>
    }
    class WeaponSetFlags {
        <<typedef BitFlags~WEAPONSET_COUNT, WeaponSetFlagsTag~>>
    }
    class DamageTypeFlags {
        <<typedef BitFlags~DAMAGE_NUM_TYPES, DamageTypeFlagsTag~>>
    }
    BitFlags <|-- KindOfMaskType : instantiates
    BitFlags <|-- DisabledMaskType : instantiates
    BitFlags <|-- ModelConditionFlags : instantiates
    BitFlags <|-- UpgradeMaskType : instantiates
    BitFlags <|-- WeaponSetFlags : instantiates
    BitFlags <|-- DamageTypeFlags : instantiates
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
classDiagram
    class BitFlags~NUMBITS, TAG~ {
        -bitset~NUMBITS~ m_bits
        +static s_bitNameList[]
        +parse(INI*, AsciiString*)
        +xfer(Xfer*)
        +parseFromINI(INI*, void*, void*, void*)
        +parseSingleBitFromINI(INI*, void*, void*, void*)
    }
    class KindOfMaskType {
        <<typedef BitFlags~KINDOF_COUNT, KindOfMaskTypeTag~>>
    }
    class DisabledMaskType {
        <<typedef BitFlags~DISABLED_COUNT, DisabledMaskTypeTag~>>
    }
    class ModelConditionFlags {
        <<typedef BitFlags~MODELCONDITION_COUNT, ModelConditionFlagsTag~>>
    }
    class UpgradeMaskType {
        <<typedef BitFlags~UPGRADE_MAX_COUNT, UpgradeMaskTypeTag~>>
    }
    class WeaponSetFlags {
        <<typedef BitFlags~WEAPONSET_COUNT, WeaponSetFlagsTag~>>
    }
    class DamageTypeFlags {
        <<typedef BitFlags~DAMAGE_NUM_TYPES, DamageTypeFlagsTag~>>
    }
    BitFlags <|-- KindOfMaskType : instantiates
    BitFlags <|-- DisabledMaskType : instantiates
    BitFlags <|-- ModelConditionFlags : instantiates
    BitFlags <|-- UpgradeMaskType : instantiates
    BitFlags <|-- WeaponSetFlags : instantiates
    BitFlags <|-- DamageTypeFlags : instantiates
Loading

Reviews (4): Last reviewed commit: "Replicate in Generals" | Re-trigger Greptile

Comment thread GeneralsMD/Code/GameEngine/Include/Common/BitFlags.h Outdated
@xezon
xezon force-pushed the xezon/fix-bitflags-names-conflicts-2 branch from 3ce4d8d to 5594615 Compare July 18, 2026 15:27
Comment thread Core/GameEngine/Include/Common/DynamicAudioEventInfo.h Outdated
@xezon
xezon force-pushed the xezon/fix-bitflags-names-conflicts-2 branch from 5594615 to ddca88f Compare July 18, 2026 17:26
Comment thread Generals/Code/GameEngine/Include/Common/BitFlagsIO.h Outdated
@xezon
xezon force-pushed the xezon/fix-bitflags-names-conflicts-2 branch from ddca88f to 8b23152 Compare July 19, 2026 08:01
@xezon
xezon merged commit da5ee97 into TheSuperHackers:main Jul 19, 2026
17 checks passed
@xezon
xezon deleted the xezon/fix-bitflags-names-conflicts-2 branch July 19, 2026 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Build Anything related to building, compiling Fix Is fixing something, but is not user facing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants