Fwd: [RFC] Proposal for tagged_by attribute to describe union discriminators
Flame Montgomery via Gcc <[email protected]> Tue, 28 Jul 2026 23:04:11 +1200
| Newsgroups | gmane.comp.gcc.devel |
|---|---|
| Message-ID | <CADbr_TLd0OapR4QatWTYsMEZY9dDtDJDnjxRaOa6WJ_doAYdGw@mail.gmail.com> |
---------- Forwarded message --------- From: Ashton Warner <[email protected]> Date: Tue, 28 Jul 2026, 11:01 pm Subject: Re: [RFC] Proposal for tagged_by attribute to describe union discriminators To: Martin Uecker <[email protected]> On Tue, Jul 28, 2026 at 09:29:07AM +0200, Martin Uecker wrote: > Am Dienstag, dem 28.07.2026 um 08:31 +0200 schrieb Richard Biener: > > On Tue, Jul 28, 2026 at 1:20=E2=80=AFAM Ashton Warner via Gcc <gcc@gcc.= gnu.org> wrote: > > > > > > On Thu, Jul 16, 2026 at 09:59:26AM +0200, Martin Uecker wrote: > > > > Am Donnerstag, dem 16.07.2026 um 09:17 +1200 schrieb Ashton Warner via Gcc: > > > > > Hello, > > > > > > > > > > I would like to discuss the possibility of adding a GCC attribute for > > > > > describing tagged unions (discriminated unions) to improve static > > > > > analysis diagnostics. > > > > > > > > > > The motivation is to allow programmers to explicitly describe a > > > > > relationship between an enum discriminator and a union member. C has a > > > > > common pattern of representing variants using a struct containing an > > > > > enum and a union: > > > > > > > > > > enum num_type { > > > > > T_INT, > > > > > T_FLOAT, > > > > > }; > > > > > > > > > > struct number { > > > > > enum num_type type; > > > > > > > > > > union { > > > > > int ival; > > > > > float fval; > > > > > }; > > > > > }; > > > > > > > > > > I propose the GCC attribute __attribute__((tagged_by(...))) with the > > > > > following syntax: > > > > > > > > > > tagged_by(discriminator, mapping-list) > > > > > > > > > > where: > > > > > > > > > > - discriminator is an identifier > > > > > - mapping-list is a comma-separated list of one or more mappings. > > > > > - Each mapping has the form: > > > > > (enumerator, union-member) > > > > > > > > > > For example: > > > > > > > > > > struct number { > > > > > enum num_type type; > > > > > > > > > > union { > > > > > int ival; > > > > > float fval; > > > > > } __attribute__((tagged_by(type, > > > > > (T_INT, ival), > > > > > (T_FLOAT, fval) > > > > > ))); > > > > > }; > > > > > > > > > > The mapping is intentionally explicit rather than inferred from the > > > > > declaration order of enum values and union members. This avoids > > > > > changing the meaning of the attribute if either the enum or union > > > > > members are reordered. > > > > > > > > > > The attribute does not change the representation or runtime behaviour > > > > > of the union. It provides additional information that GCC can use for > > > > > diagnostics and static analysis. > > > > > > > > > > For example: > > > > > > > > > > struct number n; > > > > > > > > > > n.type =3D T_INT; > > > > > n.fval =3D 1.0f; > > > > > > > > > > could produce a diagnostic because fval is not the member associated > > > > > with the current discriminator value. > > > > > > > > > > The implementation should diagnose invalid mappings, such as an > > > > > enumerator that is not part of the discriminator's enum type or a > > > > > member that does not exist in the union. > > > > > > > > > > The attribute is intended to provide semantic information in a similar > > > > > way to existing attributes such as counted_by, where the compiler is > > > > > given information about a relationship that already exists in the > > > > > program. > > > > > > > > > > > > > I agree with this proposal. There is an existing enhancement > > > > request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D112840 > > > > > > > > I like an attribute on the member more than the attribute on the > > > > union type. > > > > > > > > > Open questions: > > > > > > > > > > - How should enumerators without an associated union member be > > > > > represented? One possibility is allowing a mapping without a member, > > > > > for example (T_UNKNOWN), to explicitly indicate that an enumerator > > > > > represents a valid discriminator state with no active union member. > > > > > Enumerators that are not mentioned in the attribute could then be > > > > > diagnosed. > > > > > - Should diagnostics based on this attribute be implemented as part of > > > > > existing warning infrastructure, -fanalyzer, or another analysi= s > > > > > pass? > > > > > - Could this information be useful to future runtime checking tools? > > > > > > > > Yes, I think this would be useful for checking at run-time similar > > > > to sanitizers. This would be easy to implement. > > > > > > > > > - Are there existing GCC mechanisms that overlap with this > > > > > functionality? > > > > > - Are there additional constraints or semantics that would be needed > > > > > for GCC to implement this attribute? > > > > > > > > The issue similar to counted_by are the exact semantics for when > > > > the constraints are in effect relative to when the members are > > > > accessed / changed. > > > > > > > > Martin > > > > > > > > > > I agree with this proposal. There is an existing enhancement > > > > request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D112840 > > > > > > > > I like an attribute on the member more than the attribute on the > > > > union type. > > > > > > This proposal looks interesting and more readable than my initial > > > proposal. The one semantics that is missing from this proposal is a > > > system to allow the user to be notified when a union field does not > > > contain a tag, or when there is no field for a given enum value. > > > > > > Would an attribute that enables warning on these issues be achievable= ? > > > > > > An example of this attribute > > > > > > struct number { > > > enum num_type type; > > > > > > union { > > > int ival __attribute__((guard(.type =3D=3D T_INT)); > > > > I also think that attributes on the individual fields are better, but possibly > > combined with an attribute on the union? > > > > union { > > int ival __attribute__(tag_value(T_INT)); > > float fval __attribute__((tag_value(T_FLOAT)); > > } __attribute__((tagged_by(type))); > > > > ? > > I guess the question is whether you want to have a more constraint featur= e > or a more general, or both. My current thoughts are that a more general feature would be better and suit more developers and situations. > > I like "guard" because you can express a lot of different constraints > and tagged unions are just one possible use case. > I agree with the "guard" statements and it should be able to implement tagged unions easily while keeping the syntax available for more complex relationships. For a tagged union with warnings I would prefer to have a separate attribute that enables warning when enum values are not used in the union guard statements. union { int ival [[gnu::guard(.type =3D=3D T_INT)]]; float fval [[gnu::guard(.type =3D=3D T_FLOAT || .type =3D=3D T_NUMBER)]]; } [[gnu::warn_unused_tag(enum type, T_UNKNOWN)]]; This would satisfy the use of T_INT, T_FLOAT, T_NUMBER for the warn_unused_tag attribute despite T_FLOAT and T_NUMBER being in the same guard statement. If another value was added such as T_STR, a warning would be incurred. > > > > In principle the QUAL_UNION facility would allow having different > > tag members for different fields or even complex combined expressions > > or constants. Do we want/need > > > > union { > > int ival __attribute__(tag_value(T_INT)); > > float fval __attribute__(tag_value(T_FLOAT)); > > char pad[sizeof(union)] __attribute__((tag_default)); > > } __attribute__((tagged_by(type))); > > > > aka a fallback active element? For QUAL_UNION it would be the > > last member with a true qualifier. The behavior when no field > > is active isn't explicitly documented but you could read it to be > > that the union is empty then. > > I agree that a default tag makes sense. If we add a more constraint > version like this, I would would probably use an even shorter syntax > and reuse the "default" keyword: > > enum num_type type; > [[gnu::tagged_by(type)]] union { > [[gnu::tag(T_INT)]] int ival; > [[gnu::tag(T_FLOAT)] float fval; > [[gnu::tag(default)]] char pad[sizeof(union)]; > }; > > If the underlying feature is QUAL_UNION and this changes the size of > the union depending on the tag, I would not use attributes at all > but introduce a new __tagged_union type or something. If QUAL_UNION changes the size of the union, I would prefer to use a different feature so that ABI size is clear and matches standard union sizing. If there were a union that changed size depending on the tag, I would also prefer introducing a new type. Ashton > > Martin > > > > > > float fval; > > > } __attribute__((warn_untagged)); > > > }; > > > > > > Warning: union <anonymous> member 'fval' is untagged. <warn_untagged> > > > > > > > > > Another example showing unused enum field > > > > > > struct number { > > > enum num_type type; > > > > > > union { > > > int ival __attribute__((guard(.type =3D=3D T_INT)); > > > } __attribute__((warn_untagged(enum num_type, T_UNKNOWN))); > > > }; > > > > > > Warning: union <anonymous> missing enum value 'T_FLOAT'. <warn_untagged> > > > > > > > > > The above showing a warn_untagged that ignores the T_UNKNOWN value. > > > > > > The only issue I have with my current proposed syntax for warn_untagged > > > would be that it would be complex with the syntax of the guard attribute > > > > > > Ashton