Reputation: 53
After a compiler update from g++ v7.5 (Ubuntu 18.04) to v11.2 (Ubuntu 22.04), the following code triggers the maybe-uninitialized
warning:
#include <cstdint>
void f(std::uint16_t v)
{
(void) v;
}
int main()
{
unsigned int pixel = 0;
std::uint16_t *f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
}
Compiling on Ubuntu 22.04, g++ v11.2 with -O3 -Wall -Werror
.
The example code is a reduced form of a real use case, and its ugliness is not the issue here.
Since we have -Werror
enabled, it leads to a build error, so I'm trying figure out how to deal with it right now. Is this an instance of this gcc bug, or is there an other explanation for the warning?
https://godbolt.org/z/baaMTxhae
Upvotes: 2
Views: 331
Reputation: 40836
You don't initialize an object of type std::uint16_t
, so it is used uninitialized.
This error is suppressed by -fno-strict-aliasing
, allowing pixel
to be accessed through a uint16_t
lvalue.
Note that -fstrict-aliasing
is the default at -O2
or higher.
It could also be fixed with a may_alias
pointer:
using aliasing_uint16_t = std::uint16_t [[gnu::may_alias]];
aliasing_uint16_t* f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
Or you can use std::start_lifetime_as
:
static_assert(sizeof(int) >= sizeof(std::uint16_t) && alignof(int) >= alignof(std::uint16_t));
// (C++23, not implemented in g++11 or 12 yet)
auto *f16p = std::start_lifetime_as<std::uint16_t>(&pixel);
// (C++17)
auto *f16p = std::launder(reinterpret_cast<std::uint16_t*>(new (&pixel) char[sizeof(std::uint16_t)]));
Upvotes: 2