Bug 78044

Summary: -Wmaybe-uninitialized and -O2: false positive with boost::optional
Product: gcc Reporter: Romain Geissler <romain.geissler>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: akrzemi1, msebor
Priority: P3 Keywords: diagnostic
Version: unknown   
Target Milestone: 10.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2016-10-20 00:00:00
Bug Depends on:    
Bug Blocks: 24639    
Attachments: test.cpp
test.i
Reduced preprocessed test-case

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?
Comment 8 Martin Sebor 2021-04-12 20:57:12 UTC
The warning for the test case in comment 0 (attachment 39843 [details]) disappeared between r275012 and r275022.  The one for the test case in comment 7 disappeared after r254495.