Bug 78044 - -Wmaybe-uninitialized and -O2: false positive with boost::optional
Summary: -Wmaybe-uninitialized and -O2: false positive with boost::optional
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2016-10-19 19:25 UTC by Romain Geissler
Modified: 2017-11-06 07:40 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-10-20 00:00:00


Attachments
test.cpp (262 bytes, text/x-csrc)
2016-10-19 19:25 UTC, Romain Geissler
Details
test.i (118.29 KB, text/plain)
2016-10-19 19:26 UTC, Romain Geissler
Details
Reduced preprocessed test-case (388 bytes, text/plain)
2016-10-20 07:29 UTC, Martin Liška
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Romain Geissler 2016-10-19 19:25:30 UTC
Created attachment 39843 [details]
test.cpp

Hi,

I am having a false positive when using -O2 and -Wmaybe-uninitialized with the latest gcc 6 (g++ (GCC) 6.2.1 20160916 (Red Hat 6.2.1-2) from Fedora 24) with boost::optional. Unfortunately my attempt to reduce the test case by trying to extract the relevant boost parts failed.

Please find attached the reproducer test.cpp, that includes boost/optional.hpp (tested with boost 1.60 and 1.61, I have a warning in both cases).

g++ -std=gnu++14 -O2 -Wall -c -o test.o test.cpp
test.cpp: In function 'void someFunction(const void*)':
test.cpp:22:16: warning: '*((void*)& aOptional +4)' may be used uninitialized in this function [-Wmaybe-uninitialized]
     Optional_t aOptional;
                ^~~~~~~~~

In "someFunction()" the boost::optional value that is being passed and copied is definitely not uninitialized.

You can also find attached the preprocessor output in test.i

Cheers,
Romain
Comment 1 Romain Geissler 2016-10-19 19:26:23 UTC
Created attachment 39844 [details]
test.i
Comment 2 Andrew Pinski 2016-10-19 19:33:46 UTC
There are already filed bug reports about false positive for this warning.  This might be a dup of one of those.  

Also this warning is hard not to get false positives really for conditional unitialized variables which is why the option was split into two.  One for the hard for GCC to prove that it is not a false positive (-Wmaybe-uninitialized).
Comment 3 Andrzej Krzemienski 2016-10-20 06:34:22 UTC
"which is why the option was split into two."

Ok, it makes sense to have one reliable option that handles fewer cases, but doesn't have false positives. And another that checks more, but with false positives. The only problem I have with -Wmaybe-uninitialized is that it is included in -Wall. I thought that -Wall was meant to collect the warnings without false positives? 

Would it be possible not to turn -Wmaybe-uninitialized on when -Wall is turned on?
Comment 4 Martin Liška 2016-10-20 07:29:35 UTC
Created attachment 39848 [details]
Reduced preprocessed test-case
Comment 5 Martin Liška 2016-10-20 07:29:51 UTC
Confirmed.
Comment 6 Richard Biener 2016-10-20 07:59:13 UTC
Well.  someFunction () is optimized down to just

void someFunction() ()
{
  int aOptional$4;
  struct C D.2560;
  struct C D.2555;
  void * _4;

  <bb 2>:
  C::operator mpl_::B (&D.2555);
  D.2555 ={v} {CLOBBER};
  _4 = operator new (8);
  C::operator mpl_::B (&D.2560);

  <bb 3>:
  D.2560 ={v} {CLOBBER};
  MEM[(int *)_4 + 4B] = aOptional$4_2(D);
  return;

<L0>:
  operator delete (_4, 8);
  resx 3

so unless C::operator mpl_::B (&D.2560); always throws we store aOptional$4_2(D)
(uninitialized) to MEM[(int *)_4 + 4B].  The warning itself is a bit misleading
I guess.

Thus

    int __trans_tmp_1 = p1.get_impl ();
    new (m_storage.address ()) int(__trans_tmp_1);

and

  int
  get_impl ()
  {
    union
    {
      void *ap_pvoid;
      int *as_ptype;
    } caster{m_storage.address ()};
    get_impl___trans_tmp_3 = *caster.as_ptype;
    int __trans_tmp_2 = get_impl___trans_tmp_3;
    B __trans_tmp_4 = C ();
    return __trans_tmp_2;
  }

doesn't cover up the fact that m_storage is not initialized.

This might be an artifact of the testcase reduction of course.
Comment 7 Andrzej Krzemienski 2017-11-06 07:40:11 UTC
This still reproduces in version 7.2. Here is a Wandbox link: https://wandbox.org/permlink/5uCAr5u0xpynljhQ

Here is the code, you need to compile it with -DNDEBUG -O2:

```
#include <cassert>

class O
{
    int _val;
    bool _init = false;
public:
    O() = default;
    O(const int& i) : _val(i), _init(true) {}
    explicit operator bool () const { return _init; }
    const int& operator*() const { assert (_init); return _val; }
    void operator=(int const& i) { _init = true; _val = i; }
};

bool equal_pointees ( O const& x, O const& y )
{
  return (!x) != (!y) ? false : ( !x ? true : (*x) == (*y) ) ;
}

O getitem();

int main(int argc, const char *[])
{
  O a = getitem();
  O b;

  if (argc > 0)
    b = argc;

  if (equal_pointees(a, b))
    return 1;

  return 0;
}
```

Is there a way to give a hint to the compiler (like with an attribute) so that the warning is silenced?