[Bug c++/107919] New: Possibly false-positive "maybe-uninitialized" with GCC 12 on complex variant-variant-tuple-unique_ptr types

freddie_chopin at op dot pl gcc-bugzilla@gcc.gnu.org
Tue Nov 29 16:29:27 GMT 2022


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107919

            Bug ID: 107919
           Summary: Possibly false-positive "maybe-uninitialized" with GCC
                    12 on complex variant-variant-tuple-unique_ptr types
           Product: gcc
           Version: 12.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: freddie_chopin at op dot pl
  Target Milestone: ---

Following code gives no warning with GCC 11.3 and earlier versions:

-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --

#include <memory>
#include <variant>

using Event = std::variant<std::variant<std::tuple<std::unique_ptr<int>>>, int,
char>;

void do_something(void* storage)
{
        Event event {};
        auto& swappedValue = *reinterpret_cast<Event*>(storage);
        std::swap(event, swappedValue);
}

-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --

When compiled with GCC 12.1 or newer it reports a (possibly false-positive)
maybe-uninitialized warning that is so long, that it is hard to comprehend (;

-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --

$ g++ -std=c++17 -c -O2 warn.cpp -Wall -Wextra
In file included from /usr/include/c++/12.2.0/bits/unique_ptr.h:36,
                 from /usr/include/c++/12.2.0/memory:76,
                 from warn.cpp:1:
In constructor ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail
...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&&) [with long
unsigned int _Idx = 0; _Head = int*; _Tail = {std::default_delete<int>}]’,
    inlined from ‘constexpr std::tuple<_T1, _T2>::tuple(std::tuple<_T1, _T2>&&)
[with _T1 = int*; _T2 = std::default_delete<int>]’ at
/usr/include/c++/12.2.0/tuple:1090:17,
    inlined from ‘std::__uniq_ptr_impl<_Tp,
_Dp>::__uniq_ptr_impl(std::__uniq_ptr_impl<_Tp, _Dp>&&) [with _Tp = int; _Dp =
std::default_delete<int>]’ at /usr/include/c++/12.2.0/bits/unique_ptr.h:177:9,
    inlined from ‘std::__uniq_ptr_data<_Tp, _Dp, <anonymous>, <anonymous>
>::__uniq_ptr_data(std::__uniq_ptr_data<_Tp, _Dp, <anonymous>, <anonymous> >&&)
[with _Tp = int; _Dp = std::default_delete<int>; bool <anonymous> = true; bool
<anonymous> = true]’ at /usr/include/c++/12.2.0/bits/unique_ptr.h:234:7,
    inlined from ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp,
_Dp>&&) [with _Tp = int; _Dp = std::default_delete<int>]’ at
/usr/include/c++/12.2.0/bits/unique_ptr.h:358:7,
    inlined from ‘std::_Head_base<_Idx, _Head,
false>::_Head_base(std::_Head_base<_Idx, _Head, false>&&) [with long unsigned
int _Idx = 0; _Head = std::unique_ptr<int>]’ at
/usr/include/c++/12.2.0/tuple:196:17,
    inlined from ‘constexpr std::_Tuple_impl<_Idx,
_Head>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head>&&) [with long unsigned int
_Idx = 0; _Head = std::unique_ptr<int>]’ at
/usr/include/c++/12.2.0/tuple:456:41,
    inlined from ‘constexpr std::tuple< <template-parameter-1-1>
>::tuple(std::tuple< <template-parameter-1-1> >&&) [with _Elements =
{std::unique_ptr<int, std::default_delete<int> >}]’ at
/usr/include/c++/12.2.0/tuple:756:17,
    inlined from ‘constexpr std::__detail::__variant::_Uninitialized<_Type,
false>::_Uninitialized(std::in_place_index_t<0>, _Args&& ...) [with _Args =
{std::tuple<std::unique_ptr<int, std::default_delete<int> > >}; _Type =
std::tuple<std::unique_ptr<int, std::default_delete<int> > >]’ at
/usr/include/c++/12.2.0/variant:283:4,
    inlined from ‘constexpr std::__detail::__variant::_Variadic_union<_First,
_Rest ...>::_Variadic_union(std::in_place_index_t<0>, _Args&& ...) [with _Args
= {std::tuple<std::unique_ptr<int, std::default_delete<int> > >}; _First =
std::tuple<std::unique_ptr<int, std::default_delete<int> > >; _Rest = {}]’ at
/usr/include/c++/12.2.0/variant:385:4,
    inlined from ‘void std::_Construct(_Tp*, _Args&& ...) [with _Tp =
__detail::__variant::_Variadic_union<tuple<unique_ptr<int, default_delete<int>
> > >; _Args = {const in_place_index_t<0>&, tuple<unique_ptr<int,
default_delete<int> > >}]’ at
/usr/include/c++/12.2.0/bits/stl_construct.h:119:7,
    inlined from ‘std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)> mutable [with auto:4 =
std::tuple<std::unique_ptr<int, std::default_delete<int> > >; auto:5 =
std::integral_constant<long unsigned int, 0>]’ at
/usr/include/c++/12.2.0/variant:605:23,
    inlined from ‘constexpr _Res std::__invoke_impl(__invoke_other, _Fn&&,
_Args&& ...) [with _Res = void; _Fn =
__detail::__variant::_Move_ctor_base<false, tuple<unique_ptr<int,
default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>; _Args = {tuple<unique_ptr<int,
default_delete<int> > >, integral_constant<long unsigned int, 0>}]’ at
/usr/include/c++/12.2.0/bits/invoke.h:61:36,
    inlined from ‘constexpr typename std::__invoke_result<_Functor,
_ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable =
__detail::__variant::_Move_ctor_base<false, tuple<unique_ptr<int,
default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>; _Args = {tuple<unique_ptr<int,
default_delete<int> > >, integral_constant<long unsigned int, 0>}]’ at
/usr/include/c++/12.2.0/bits/invoke.h:96:40,
    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
= std::__detail::__variant::__variant_idx_cookie; _Visitor =
std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>&&; _Variants =
{std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&}; long unsigned int ...__indices = {0}]’ at
/usr/include/c++/12.2.0/variant:1020:17,
    inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&,
_Variants&& ...) [with _Result_type =
__detail::__variant::__variant_idx_cookie; _Visitor =
__detail::__variant::_Move_ctor_base<false, tuple<unique_ptr<int,
default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>; _Variants = {variant<tuple<unique_ptr<int,
default_delete<int> > > >}]’ at /usr/include/c++/12.2.0/variant:1783:5,
    inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&,
_Variants&& ...) [with _Result_type =
__detail::__variant::__variant_idx_cookie; _Visitor =
__detail::__variant::_Move_ctor_base<false, tuple<unique_ptr<int,
default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>; _Variants = {variant<tuple<unique_ptr<int,
default_delete<int> > > >}]’ at /usr/include/c++/12.2.0/variant:1729:5,
    inlined from ‘constexpr void
std::__detail::__variant::__raw_idx_visit(_Visitor&&, _Variants&& ...) [with
_Visitor = _Move_ctor_base<false, std::tuple<std::unique_ptr<int,
std::default_delete<int> > >
>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>&&)::<lambda(auto:4&&, auto:5)>; _Variants =
{std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int> > > >}]’
at /usr/include/c++/12.2.0/variant:184:44,
    inlined from ‘std::__detail::__variant::_Move_ctor_base<<anonymous>,
_Types>::_Move_ctor_base(std::__detail::__variant::_Move_ctor_base<<anonymous>,
_Types>&&) [with bool <anonymous> = false; _Types =
{std::tuple<std::unique_ptr<int, std::default_delete<int> > >}]’ at
/usr/include/c++/12.2.0/variant:600:28,
    inlined from ‘std::__detail::__variant::_Copy_assign_base<<anonymous>,
_Types>::_Copy_assign_base(std::__detail::__variant::_Copy_assign_base<<anonymous>,
_Types>&&) [with bool <anonymous> = false; _Types =
{std::tuple<std::unique_ptr<int, std::default_delete<int> > >}]’ at
/usr/include/c++/12.2.0/variant:665:7,
    inlined from ‘std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>::_Move_assign_base(std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>&&) [with bool <anonymous> = false; _Types =
{std::tuple<std::unique_ptr<int, std::default_delete<int> > >}]’ at
/usr/include/c++/12.2.0/variant:719:7,
    inlined from
‘std::__detail::__variant::_Variant_base<_Types>::_Variant_base(std::__detail::__variant::_Variant_base<_Types>&&)
[with _Types = {std::tuple<std::unique_ptr<int, std::default_delete<int> > >}]’
at /usr/include/c++/12.2.0/variant:750:7,
    inlined from ‘std::variant<_Types>::variant(std::variant<_Types>&&) [with
_Types = {std::tuple<std::unique_ptr<int, std::default_delete<int> > >}]’ at
/usr/include/c++/12.2.0/variant:1404:7,
    inlined from ‘void std::_Construct(_Tp*, _Args&& ...) [with _Tp =
variant<tuple<unique_ptr<int, default_delete<int> > > >; _Args =
{variant<tuple<unique_ptr<int, default_delete<int> > > >}]’ at
/usr/include/c++/12.2.0/bits/stl_construct.h:119:7,
    inlined from ‘void
std::__detail::__variant::__emplace(_Variant_storage<_Triv, _Types ...>&,
_Args&& ...) [with long unsigned int _Np = 0; bool _Triv = false; _Types =
{std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int> > > >,
int, char}; _Args = {std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >}]’ at /usr/include/c++/12.2.0/variant:541:22,
    inlined from ‘std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>
mutable [with auto:22 = std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >&; auto:23 = std::integral_constant<long unsigned
int, 0>]’ at /usr/include/c++/12.2.0/variant:1650:32,
    inlined from ‘constexpr _Res std::__invoke_impl(__invoke_other, _Fn&&,
_Args&& ...) [with _Res = void; _Fn = variant<variant<tuple<unique_ptr<int,
default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>;
_Args = {variant<tuple<unique_ptr<int, default_delete<int> > > >&,
integral_constant<long unsigned int, 0>}]’ at
/usr/include/c++/12.2.0/bits/invoke.h:61:36,
    inlined from ‘constexpr typename std::__invoke_result<_Functor,
_ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable =
variant<variant<tuple<unique_ptr<int, default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>;
_Args = {variant<tuple<unique_ptr<int, default_delete<int> > > >&,
integral_constant<long unsigned int, 0>}]’ at
/usr/include/c++/12.2.0/bits/invoke.h:96:40,
    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
= std::__detail::__variant::__variant_idx_cookie; _Visitor =
std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>&&;
_Variants = {std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&}; long unsigned int ...__indices =
{0}]’ at /usr/include/c++/12.2.0/variant:1020:17,
    inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&,
_Variants&& ...) [with _Result_type =
__detail::__variant::__variant_idx_cookie; _Visitor =
variant<variant<tuple<unique_ptr<int, default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>;
_Variants = {variant<variant<tuple<unique_ptr<int, default_delete<int> > > >,
int, char>&}]’ at /usr/include/c++/12.2.0/variant:1783:5,
    inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&,
_Variants&& ...) [with _Result_type =
__detail::__variant::__variant_idx_cookie; _Visitor =
variant<variant<tuple<unique_ptr<int, default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>;
_Variants = {variant<variant<tuple<unique_ptr<int, default_delete<int> > > >,
int, char>&}]’ at /usr/include/c++/12.2.0/variant:1729:5,
    inlined from ‘constexpr void
std::__detail::__variant::__raw_idx_visit(_Visitor&&, _Variants&& ...) [with
_Visitor = std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int,
char>::swap(std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&)::<lambda(auto:22&&, auto:23)>;
_Variants = {std::variant<std::variant<std::tuple<std::unique_ptr<int,
std::default_delete<int> > > >, int, char>&}]’ at
/usr/include/c++/12.2.0/variant:184:44,
    inlined from ‘void std::variant<_Types>::swap(std::variant<_Types>&) [with
_Types = {std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int>
> > >, int, char}]’ at /usr/include/c++/12.2.0/variant:1623:28,
    inlined from ‘std::enable_if_t<((is_move_constructible_v<_Types> && ...) &&
(is_swappable_v<_Types> && ...))> std::swap(variant<_Types ...>&,
variant<_Types ...>&) [with _Types = {variant<tuple<unique_ptr<int,
default_delete<int> > > >, int, char}]’ at
/usr/include/c++/12.2.0/variant:1297:17,
    inlined from ‘void do_something(void*)’ at warn.cpp:10:11:
/usr/include/c++/12.2.0/tuple:301:7: warning: ‘*(int**)((char*)&__tmp +
offsetof(std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int>
> > >,std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Variant_base<std::tuple<std::unique_ptr<int,
std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Move_assign_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Copy_assign_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Copy_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Variant_storage<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > > >::_M_u))’ may be
used uninitialized [-Wmaybe-uninitialized]
  301 |       _Tuple_impl(_Tuple_impl&&) = default;
      |       ^~~~~~~~~~~
In file included from warn.cpp:2:
/usr/include/c++/12.2.0/variant: In function ‘void do_something(void*)’:
/usr/include/c++/12.2.0/variant:1636:26: note: ‘*(int**)((char*)&__tmp +
offsetof(std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int>
> > >,std::variant<std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Variant_base<std::tuple<std::unique_ptr<int,
std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Move_assign_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Copy_assign_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Move_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Copy_ctor_base<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > >
>::<unnamed>.std::__detail::__variant::_Variant_storage<false,
std::tuple<std::unique_ptr<int, std::default_delete<int> > > >::_M_u))’ was
declared here
 1636 |                     auto __tmp(std::move(__rhs_mem));
      |                          ^~~~~

-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --

Above warning is with GCC 12.2 on PC (linux), but I also get a similar (or
identical, hard to see) warning for 12.1 (tested for arm-none-eabi target, as I
have multiple versions of the compiler at hand).

It seems as if any change in the test-case above will make the warning go away,
even changes which should not make much difference - for example reducing the
number of types in the "outer" variant from 3 to 2 or just putting the "complex
type" inside a struct or renaming `Event` to sth else and creating a struct
called `Event` which inherits the "complex type". But things like avoiding the
tuple, avoiding unique_ptr, avoiding variant-in-variant - each one makes the
warning disappear. Also using a "real" object instead of casted `void*` storage
"solves" the problem, however this particular code is part of a low-level
embedded RTOS and I would really prefer to keep using `void*` in this case. But
as I mentioned, even with casted `void*` but slightly simpler/different `Event`
type, the warning is gone.

Note - having optional-in-variant also produces mostly identical warning.

I'm not sure whether this is intended behavior and my code is indeed wrong or
maybe this is a regression.


More information about the Gcc-bugs mailing list