title: std::optional default constructor not being constexpr in gcc?
body: <p>I have the following code to test my constexpr-constructible lazy class:</p>
  
  <p><a href="https://godbolt.org/z/rMLCiL" rel="nofollow noreferrer">https://godbolt.org/z/rMLCiL</a></p>
  
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;optional&gt;
  
  template &lt;class T&gt;
  class Lazy
  {
  
      using initializer_t = T (*)();
      std::optional&lt;T&gt; m_val = std::nullopt;
      initializer_t m_initializer;
  
  public:
      constexpr Lazy(initializer_t initializer = initializer_t{[] { return T{}; }}) noexcept
          : m_initializer{initializer} {}
  
      T&amp; operator*()
      {
          if (!m_val.has_value()) {
              m_val = m_initializer();
          }
          return *m_val;
      }
      constexpr T* operator-&gt;() { return &amp;(**this); }
  };
  
  
  #include &lt;iostream&gt;
  struct A {
      int f() { return 10; }
      ~A()
      {
          std::cout &lt;&lt; "Goodbye A " &lt;&lt; (void*)this &lt;&lt; std::endl;
      }
  };
  extern Lazy&lt;A&gt; a;
  
  int val = a-&gt;f();
  
  Lazy&lt;A&gt; a{[] { return A{}; }};
  
  int main()
  {
      std::cout &lt;&lt; val &lt;&lt; std::endl;
  }
  </code></pre>
  
  <p>I expect it to print 10 in <code>main</code>. When compiled in clang-8.0, it runs as expected, but when compiled in gcc (either in 8.3 or in trunk), it causes a segmentation fault. It seems that <code>a</code> is not <a href="https://en.cppreference.com/w/cpp/language/constant_initialization" rel="nofollow noreferrer">constant-initialized</a>, and it's calling null <code>a.m_initializer</code> inside <code>int val = a-&gt;f()</code> before <code>a</code> gets initialized.</p>
  
  <p><a href="https://en.cppreference.com/w/cpp/utility/optional/optional" rel="nofollow noreferrer">Cppreference</a> says that <code>std::optional&lt;T&gt;</code> can be initialized to std::nullopt using a <code>constexpr</code> constructor, whether T is trivially-destructible or not. Thus, <code>Lazy&lt;A&gt; a{[] { return A{}; }}</code> should be constant-initialized before <code>int val = a-&gt;f();</code> is initialized. If I comment out <code>A::~A</code>, it will run as expected even when compiled with gcc. Is this a bug in gcc, or am I missing something? </p>
  
  <p><strong>Update</strong>: I also found that if I make <code>std::optional&lt;T&gt;</code> a base class instead of having such member, it works correctly in gcc. Also, if I just change the line <code>std::optional&lt;T&gt; m_val = std::nullopt;</code> to <code>std::optional&lt;T&gt; m_val;</code>, it works correctly (<code>std::optional&lt;T&gt; m_val{};</code> doesn't work). I don't really understand.</p>