[Bug c++/80635] std::optional and bogus -Wmaybe-uninitialized warning

palves at redhat dot com gcc-bugzilla@gcc.gnu.org
Fri May 5 09:26:00 GMT 2017


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

--- Comment #4 from Pedro Alves <palves at redhat dot com> ---
Hi Marc, thanks much for taking a look.

Looks like I over reduced in the minimal reproducer.  std::optional has a
boolean field to track whether the contained object had been fully initialized,
which is checked in the desctructor, but I removed it because its presence
doesn't affect whether the warning is emitted.  Of course, std::optional has
that field, but still, it warns.

A couple of things that look suspiciously odd to me, even in the
original testcase:

 - the warning is about A::m_dummy, while optional::~optional calls the 
   m_item/T's destructor, not m_dummy's.

 - the warning triggers in A/optional<A>, but for some reason, only if
   B/optional<B> exist, as well as the maybe_b variable, which are all
   completely unrelated to A.  This one makes me wonder if there's some
   miscompilation related to aliasing or or object lifetimes going on,
   not just a warning.

Here's the corrected testcase:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ cat optional2.cc
//#include <optional>
//#include <experimental/optional>
#include <new>

template<typename T>
struct optional
{
  optional ()
    : m_dummy (),
      m_instantiated (false)
  {}

  ~optional ()
  {
    if (m_instantiated)
      m_item.~T (); // won't run unless T is fully constructed.
  }

  void emplace ()
  {
    new (&m_item) T ();
    m_instantiated = true; // not set if T() throws
  }

  union
  {
    int m_dummy;
    T m_item;
  };

  bool m_instantiated;
};

template <typename T>
using Optional = optional<T>; // warns
//using Optional = std::experimental::optional<T>; // warns too
//using Optional = std::optional<T>; // warns too

extern int get ();
extern void set (int);

struct A
{
  A () : m (get ()) {} // warns here
  ~A () { set (m); }

  int m;
};

// for some reason, need B to trigger the warning.
struct B
{
  B (); // remove or make noexcept, and the warning disappears
  ~B (); // remove, and the warning disappears
};

void func ()
{
  Optional<A> maybe_a;
  Optional<B> maybe_b; // for some reason, need this here to trigger a
                       // warning in _A_.

  maybe_a.emplace ();
  maybe_b.emplace (); // comment out, and the warning disappears.
}

$ /opt/gcc/bin/g++ optional2.cc -O2 -Wall -c 
optional2.cc: In function ‘void func()’:
optional2.cc:45:15: warning:
‘maybe_a.optional<A>::<anonymous>.optional<A>::<unnamed union>::m_dummy’ may be
used uninitialized in this function [-Wmaybe-uninitialized]
   ~A () { set (m); }
           ~~~~^~~
optional2.cc:59:15: note:
‘maybe_a.optional<A>::<anonymous>.optional<A>::<unnamed union>::m_dummy’ was
declared here
   Optional<A> maybe_a;
               ^~~~~~~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Do you see anything invalid in this version of the test?


More information about the Gcc-bugs mailing list