I've reduced my code to the following example, which fails -O3 C++20 compilation on my g++ (x64 12.3) as well as apparently 14.1 when using godbolt:
Again according to godbolt, clang works without any warnings. Is the warning valid, or a bug in GCC?
Here is my code. Apologies for the length; I tried to be minimal, but the warning is not predictable nor easy to trigger.
#include <cassert>
#include <cstdlib>
#include <optional>
#include <string>
#include <utility>
using namespace std;
class HS {
public:
constexpr HS() = default;
constexpr explicit HS(string_view view) : _view(view) {}
constexpr HS(HS const& other) { *this = other; }
constexpr HS& operator=(HS const& other) {
_stringOpt = other._stringOpt;
_view = _stringOpt ? string_view{*_stringOpt} : other._view;
return *this;
}
constexpr HS& operator=(HS&& other) noexcept {
if (this != &other) {
_stringOpt =
std::exchange(/*inout*/ other._stringOpt, std::nullopt);
_view = _stringOpt ? string_view{*_stringOpt} : other._view;
other._view = k_empty;
}
return *this;
}
private:
static constexpr char const* k_empty = "";
optional<string> _stringOpt;
string_view _view = k_empty;
};
inline HS operator""_hs(char const* string, size_t length) noexcept {
return HS(string_view{string, length});
}
HS bar(HS const& hs) { return rand() < 10000 ? "sdok"_hs : hs; }
int func() {
HS foo;
try {
foo = "1"_hs;
foo = bar(foo);
foo = "2"_hs; // <--- warning is about this
} catch (...) {
return 1;
}
return 0;
}
// No warning if body of func() is placed inside main()
int main() { return func(); }
I get this warning (treated as error):
In file included from /opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/string:54,
from <source>:5:
In member function 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]',
inlined from 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator __sv_type() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_string.h:950:16,
inlined from 'constexpr HS& HS::operator=(HS&&)' at <source>:28:57,
inlined from 'constexpr HS& HS::operator=(HS&&)' at <source>:24:19,
inlined from 'int func()' at <source>:52:15:
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_string.h:1077:16: error: '*(const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)((char*)&foo + offsetof(HS, HS::_stringOpt.std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::<unnamed>.std::_Optional_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false, false>::<unnamed>)).std::__cxx11::basic_string<char>::_M_string_length' may be used uninitialized [-Werror=maybe-uninitialized]
1077 | { return _M_string_length; }
| ^~~~~~~~~~~~~~~~
<source>: In function 'int func()':
<source>:48:8: note: 'foo' declared here
48 | HS foo;
| ^~~
In member function 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::pointer std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_data() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]',
inlined from 'constexpr const _CharT* std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::data() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_string.h:2654:23,
inlined from 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator __sv_type() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_string.h:950:16,
inlined from 'constexpr HS& HS::operator=(HS&&)' at <source>:28:57,
inlined from 'constexpr HS& HS::operator=(HS&&)' at <source>:24:19,
inlined from 'int func()' at <source>:52:15:
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/basic_string.h:228:28: error: '*(const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)((char*)&foo + offsetof(HS, HS::_stringOpt.std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::<unnamed>.std::_Optional_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false, false>::<unnamed>)).std::__cxx11::basic_string<char>::_M_dataplus.std::__cxx11::basic_string<char>::_Alloc_hider::_M_p' may be used uninitialized [-Werror=maybe-uninitialized]
228 | { return _M_dataplus._M_p; }
| ^~~~
<source>: In function 'int func()':
<source>:48:8: note: 'foo' declared here
48 | HS foo;
| ^~~
cc1plus: all warnings being treated as errors
Compiler returned: 1