bugprone-tagged-union-member-count¶
Gives warnings for tagged unions, where the number of tags is different from the number of data members inside the union.
A struct or a class is considered to be a tagged union if it has exactly one union data member and exactly one enum data member and any number of other data members that are neither unions or enums.
Example:
enum Tags {
Tag1,
Tag2,
};
struct TaggedUnion { // warning: tagged union has more data members (3) than tags (2)
enum Tags Kind;
union {
int I;
float F;
char *Str;
} Data;
};
How enum constants are counted¶
The main complicating factor when counting the number of enum constants is that some of them might be auxiliary values that purposefully don’t have a corresponding union data member and are used for something else. For example the last enum constant sometimes explicitly “points to” the last declared valid enum constant or tracks how many enum constants have been declared.
For an illustration:
enum TagWithLast {
Tag1 = 0,
Tag2 = 1,
Tag3 = 2,
LastTag = 2
};
enum TagWithCounter {
Tag1, // is 0
Tag2, // is 1
Tag3, // is 2
TagCount, // is 3
};
The check counts the number of distinct values among the enum constants and not the enum constants themselves. This way the enum constants that are essentially just aliases of other enum constants are not included in the final count.
Handling of counting enum constants (ones like TagCount
in the previous code example)
is done by decreasing the number of enum values by one if the name of the last enum constant
starts with a prefix or ends with a suffix specified in CountingEnumPrefixes
,
CountingEnumSuffixes
and it’s value is one less than the total number of distinct
values in the enum.
When the final count is adjusted based on this heuristic then a diagnostic note is emitted that shows which enum constant matched the criteria.
The heuristic can be disabled entirely (EnableCountingEnumHeuristic
) or
configured to follow your naming convention (CountingEnumPrefixes
, CountingEnumSuffixes
).
The strings specified in CountingEnumPrefixes
, CountingEnumSuffixes
are matched
case insensitively.
Example counts:
// Enum count is 3, because the value 2 is counted only once
enum TagWithLast {
Tag1 = 0,
Tag2 = 1,
Tag3 = 2,
LastTag = 2
};
// Enum count is 3, because TagCount is heuristically excluded
enum TagWithCounter {
Tag1, // is 0
Tag2, // is 1
Tag3, // is 2
TagCount, // is 3
};
Options¶
- EnableCountingEnumHeuristic¶
This option enables or disables the counting enum heuristic.
It uses the prefixes and suffixes specified in the options
CountingEnumPrefixes
, CountingEnumSuffixes
to find counting enum constants by
using them for prefix and suffix matching.
This option is enabled by default.
When EnableCountingEnumHeuristic
is false:
enum TagWithCounter {
Tag1,
Tag2,
Tag3,
TagCount,
};
struct TaggedUnion {
TagWithCounter Kind;
union {
int A;
long B;
char *Str;
float F;
} Data;
};
When EnableCountingEnumHeuristic
is true:
enum TagWithCounter {
Tag1,
Tag2,
Tag3,
TagCount,
};
struct TaggedUnion { // warning: tagged union has more data members (4) than tags (3)
TagWithCounter Kind;
union {
int A;
long B;
char *Str;
float F;
} Data;
};
- CountingEnumPrefixes¶
See CountingEnumSuffixes
below.
- CountingEnumSuffixes¶
CountingEnumPrefixes and CountingEnumSuffixes are lists of semicolon
separated strings that are used to search for possible counting enum constants.
These strings are matched case insensitively as prefixes and suffixes
respectively on the names of the enum constants.
If EnableCountingEnumHeuristic
is false then these options do nothing.
The default value of CountingEnumSuffixes
is count and of
CountingEnumPrefixes
is the empty string.
When EnableCountingEnumHeuristic
is true and CountingEnumSuffixes
is count;size:
enum TagWithCounterCount {
Tag1,
Tag2,
Tag3,
TagCount,
};
struct TaggedUnionCount { // warning: tagged union has more data members (4) than tags (3)
TagWithCounterCount Kind;
union {
int A;
long B;
char *Str;
float F;
} Data;
};
enum TagWithCounterSize {
Tag11,
Tag22,
Tag33,
TagSize,
};
struct TaggedUnionSize { // warning: tagged union has more data members (4) than tags (3)
TagWithCounterSize Kind;
union {
int A;
long B;
char *Str;
float F;
} Data;
};
When EnableCountingEnumHeuristic
is true and CountingEnumPrefixes
is maxsize;last_
enum TagWithCounterLast {
Tag1,
Tag2,
Tag3,
last_tag,
};
struct TaggedUnionLast { // warning: tagged union has more data members (4) than tags (3)
TagWithCounterLast tag;
union {
int I;
short S;
char *C;
float F;
} Data;
};
enum TagWithCounterMaxSize {
Tag1,
Tag2,
Tag3,
MaxSizeTag,
};
struct TaggedUnionMaxSize { // warning: tagged union has more data members (4) than tags (3)
TagWithCounterMaxSize tag;
union {
int I;
short S;
char *C;
float F;
} Data;
};
- StrictMode¶
When enabled, the check will also give a warning, when the number of tags is greater than the number of union data members.
This option is disabled by default.
When StrictMode
is false:
struct TaggedUnion {
enum {
Tag1,
Tag2,
Tag3,
} Tags;
union {
int I;
float F;
} Data;
};
When StrictMode
is true:
struct TaggedUnion { // warning: tagged union has fewer data members (2) than tags (3)
enum {
Tag1,
Tag2,
Tag3,
} Tags;
union {
int I;
float F;
} Data;
};