Skip to content

core::Container::operator*() trips -Wcast-align for over-aligned types #40

Description

@erik-rainey-neurophos

Summary

core::Container<TYPE>::operator*() casts the raw std::uint8_t storage to TYPE* with reinterpret_cast, which trips -Werror=cast-align for any TYPE whose alignment is greater than 1. This is currently latent — Pool only ever reaches the storage through operator-> — but any use of operator* on a Container holding an over-aligned type fails to compile under a strict build. Against main (commit c66a0d2).

Details

modules/core/include/core/Container.hpp (~lines 78–85):

TYPE& operator*() {
    if (that_) {
        return *that_;
    } else {
        // this is potentially uninitialized or undefined storage!
        return *reinterpret_cast<TYPE*>(&storage_[0]);
    }
}

with the backing storage declared (line ~103):

alignas(alignof(TYPE)) std::uint8_t storage_[sizeof(TYPE)];

&storage_[0] has type std::uint8_t* (alignment 1). Casting it to TYPE* when alignof(TYPE) > 1 makes GCC's -Wcast-align warn (and fail under -Werror):

error: cast from 'uint8_t*' {aka 'unsigned char*'} to 'T*' increases required alignment of target type [-Werror=cast-align]

The cast is in fact safestorage_ is declared alignas(alignof(TYPE)), so the pointer is correctly aligned — but the compiler only sees the uint8_t element type at the point of the cast, so the diagnostic is a false positive.

Why it's latent today

Pool<TYPE, N> accesses elements via operator-> (which returns that_ directly, no cast), so operator*'s else branch is never instantiated for an aligned type in the current tree. It surfaces the moment operator* is instantiated for a Container of an over-aligned type (a class with alignof > 1, e.g. anything containing a pointer or 4/8-byte field). It would also bite the on-target build, which compiles with -Wcast-align -Werror.

Suggested fix

Route the cast through void*, which is well-defined given the alignas storage and suppresses the false-positive warning:

return *static_cast<TYPE*>(static_cast<void*>(&storage_[0]));

(Same note as the existing comment applies: this branch still returns a reference to not-yet-constructed storage; only the cast is being made portable.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions