Skip to content

Core: Purge remaining unions in math structs#120845

Open
Repiteo wants to merge 1 commit into
godotengine:masterfrom
Repiteo:core/union-busting
Open

Core: Purge remaining unions in math structs#120845
Repiteo wants to merge 1 commit into
godotengine:masterfrom
Repiteo:core/union-busting

Conversation

@Repiteo

@Repiteo Repiteo commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What problem(s) does this PR solve?

Mirrors the above goal to make AudioFrame trivially copyable; now extended to Vector2, Vector2i, Vector3, Vector3i, Vector4, Vector4i, Quaternion, and Color

Additional information

A few areas of code were relying on Color array access directly, but were able to be worked around by reinterpreting the struct itself as a container of floats (which, functionally, it is). Beyond that, the bracket accessors were all made constexpr and given proper DEV_ASSERT checks if they weren't already present

@Repiteo Repiteo added this to the 4.x milestone Jul 2, 2026
@Repiteo Repiteo requested review from a team as code owners July 2, 2026 00:48
@Repiteo Repiteo removed request for a team July 2, 2026 00:49
@lawnjelly

Copy link
Copy Markdown
Member

Isn't this major compat breaking in third party code?

@Ivorforce

Ivorforce commented Jul 2, 2026

Copy link
Copy Markdown
Member

Isn't this major compat breaking in third party code?

Only if they actually use it (which, since we don't internally, they're unlikely too a well, I'd wager).

Also, we don't guarantee code compat paths for modules — code health trumps. GDExtensions are unaffected by this change.

Comment thread core/math/quaternion.h Outdated
Comment thread core/math/audio_frame.h Outdated
template <>
struct is_zero_constructible<AudioFrame> : std::true_type {};

static_assert(offsetof(AudioFrame, left) == 0 * sizeof(float));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we made some "style decisions" these on #120840

Can you make sure these all look the same, and that all of these contain the same comment?

I really want to make sure that if this ever breaks for anyone that the comment is right there to explain what happened.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented! Slightly tweaked the text so that all instances can reuse the same blurb & no longer exceeds a width of 100

glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);

glClearBufferfv(GL_COLOR, 0, rt->clear_color.components);
glClearBufferfv(GL_COLOR, 0, &rt->clear_color.r);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this at all, I realize that that is perhaps not a great comment, but this is confusing.

The old code was way more readable. This should just work with &rt->clear_color I think. If we can't make that work reasonably then I don't know if we should be doing this for this type.

I'd be way happier with an explicit cast, or even a method that does something sensible that is always inline.

But this I hate with the passion of a thousand suns.

@hpvb hpvb Jul 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean to say is, that the UB fuckery should be entirely hidden inside the class. Now we're telling the outside world as well that &color.r++ == &color.b

Maybe that's a bit more explanatory than my previous comment. :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like this?

float *as_float4_buffer() {
    return &r; // encapsulate the evil inside the function
}

glClearBufferfv(GL_COLOR, 0, &rt->clear_color.as_float4_buffer());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be 100% fine with that!

Alternatively maybe a operator float(&)[4]() that should be pretty safe, since it's an array type it won't just magically turn into a bool either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't appear like there's any way to make a return value for a carray without actually referencing a carray in some form. In the interest of keeping it simple, I opted for as_float4_buffer()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interest of keeping it simple, I opted for as_float4_buffer()

Perfect! My dislike for that is measurable in a low 100s amount of joules.

@Repiteo Repiteo force-pushed the core/union-busting branch from f60a476 to 60a16ad Compare July 3, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants