https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116026
Bug ID: 116026 Summary: Copying or moving a std::variant that can be a vector causes a maybe-uninitialized warning with -fsanitize=address -Og -finline-functions-called-once Product: gcc Version: 14.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: sebastian.r.gracia at gmail dot com CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org Target Milestone: --- How to reproduce: > cat code.cpp #include <variant> #include <vector> extern "C" int printf(const char *, ...); using node = std::variant<std::vector<int>, int>; int main() { int a{15}; [[maybe_unused]] node b = a; // line 1 // printf("%d", std::get<int>(b)); // line 2 } > g++ -Werror=maybe-uninitialized -fsanitize=address -Og > -finline-functions-called-once code.cpp In file included from /usr/include/c++/14.1.1/vector:66, from code.cpp:2: In destructor ‘std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = int; _Alloc = std::allocator<int>]’, inlined from ‘std::vector<_Tp, _Alloc>::~vector() [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/14.1.1/bits/stl_vector.h:738:7, inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = vector<int>]’ at /usr/include/c++/14.1.1/bits/stl_construct.h:151:22, inlined from ‘std::__detail::__variant::_Variant_storage<false, std::vector<int, std::allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)> mutable [with auto:1 = std::vector<int>&]’ at /usr/include/c++/14.1.1/variant:498:19, inlined from ‘constexpr _Res std::__invoke_impl(__invoke_other, _Fn&&, _Args&& ...) [with _Res = void; _Fn = __detail::__variant::_Variant_storage<false, vector<int, allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>; _Args = {vector<int, allocator<int> >&}]’ at /usr/include/c++/14.1.1/bits/invoke.h:61:36, inlined from ‘constexpr std::enable_if_t<((bool)is_invocable_r_v<_Res, _Callable, _Args ...>), _Res> std::__invoke_r(_Callable&&, _Args&& ...) [with _Res = void; _Callable = __detail::__variant::_Variant_storage<false, vector<int, allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>; _Args = {vector<int, allocator<int> >&}]’ at /usr/include/c++/14.1.1/bits/invoke.h:111:28, inlined from ‘static constexpr decltype(auto) std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int, __indices ...> >::__visit_invoke(_Visitor&&, _Variants ...) [with _Result_type = void; _Visitor = std::__detail::__variant::_Variant_storage<false, std::vector<int, std::allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>&&; _Variants = {std::variant<std::vector<int, std::allocator<int> >, int>&}; long unsigned int ...__indices = {0}]’ at /usr/include/c++/14.1.1/variant:1064:40, inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&, _Variants&& ...) [with _Result_type = void; _Visitor = __detail::__variant::_Variant_storage<false, vector<int, allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>; _Variants = {variant<vector<int, allocator<int> >, int>&}]’ at /usr/include/c++/14.1.1/variant:1816:5, inlined from ‘constexpr void std::__detail::__variant::_Variant_storage<false, _Types ...>::_M_reset() [with _Types = {std::vector<int, std::allocator<int> >, int}]’ at /usr/include/c++/14.1.1/variant:496:23, inlined from ‘std::__detail::__variant::_Variant_storage<false, _Types ...>::~_Variant_storage() [with _Types = {std::vector<int, std::allocator<int> >, int}]’ at /usr/include/c++/14.1.1/variant:506:17, inlined from ‘std::__detail::__variant::_Copy_ctor_base<false, std::vector<int, std::allocator<int> >, int>::~_Copy_ctor_base()’ at /usr/include/c++/14.1.1/variant:581:12, inlined from ‘std::__detail::__variant::_Move_ctor_base<false, std::vector<int, std::allocator<int> >, int>::~_Move_ctor_base()’ at /usr/include/c++/14.1.1/variant:618:12, inlined from ‘std::__detail::__variant::_Copy_assign_base<false, std::vector<int, std::allocator<int> >, int>::~_Copy_assign_base()’ at /usr/include/c++/14.1.1/variant:656:12, inlined from ‘std::__detail::__variant::_Move_assign_base<false, std::vector<int, std::allocator<int> >, int>::~_Move_assign_base()’ at /usr/include/c++/14.1.1/variant:708:12, inlined from ‘std::__detail::__variant::_Variant_base<std::vector<int, std::allocator<int> >, int>::~_Variant_base()’ at /usr/include/c++/14.1.1/variant:762:12, inlined from ‘std::variant<_Types>::~variant() [with _Types = {std::vector<int, std::allocator<int> >, int}]’ at /usr/include/c++/14.1.1/variant:1435:28, inlined from ‘int main()’ at code.cpp:12:1: /usr/include/c++/14.1.1/bits/stl_vector.h:369:31: error: ‘*(std::_Vector_base<int, std::allocator<int> >*)((char*)&b + offsetof(std::node, std::variant<std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Variant_base<std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Move_assign_base<false, std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Copy_assign_base<false, std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Move_ctor_base<false, std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Copy_ctor_base<false, std::vector<int, std::allocator<int> >, int>::<unnamed>.std::__detail::__variant::_Variant_storage<false, std::vector<int, std::allocator<int> >, int>::_M_u)).std::_Vector_base<int, std::allocator<int> >::_M_impl.std::_Vector_base<int, std::allocator<int> >::_Vector_impl::std::_Vector_base<int, std::allocator<int> >::_Vector_impl_data.std::_Vector_base<int, std::allocator<int> >::_Vector_impl_data::_M_end_of_storage’ may be used uninitialized [-Werror=maybe-uninitialized] 369 | _M_impl._M_end_of_storage - _M_impl._M_start); | ~~~~~~~~^~~~~~~~~~~~~~~~~ code.cpp: In function ‘int main()’: code.cpp:10:27: note: ‘b’ declared here 10 | [[maybe_unused]] node b = a; // line 1 | ^ cc1plus: some warnings being treated as errors > g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 14.1.1 20240522 (GCC) Weird behaviors noticed: - Using -fsanitize=address,undefined causes no warning - Defining _GLIBCXX_DEBUG (with -D_GLIBCXX_DEBUG) negates the issue - Warning persists when changing 'line 1' to use std::move (identical except for note at bottom and line number changes from including <utility>) - No compile warning is issued when 'line 2' is uncommented - When adding another line that uses std::move, no warning is issued, despite both lines causing the warnings on their own I used to have a related version of this issue with a different core warning/error, but I can no longer reproduce it. All I can remember is that it was also a maybe-uninitialized warning, and that it concerned an assignment statement instead of a subtraction expression. Additionally, in that issue, using a struct inheriting from std::variant, with 'using variant::variant;' inside, caused the warning, whereas a using-declaration did not. It was probably in an older version of gcc, though I can't say for sure.