title: Why does Return Value Optimization not happen if no destructor is defined?
body: <p>I expected to see <a href="https://stackoverflow.com/a/12953129/2319122">copy elision</a> from Named Return Value Optimization (NRVO) from this test program but its output is &quot;Addresses do not match!&quot; so NRVO didn't happen.  Why is this?</p>
  <pre><code>// test.cpp
  // Compile using:
  //      g++ -Wall -std=c++17 -o test test.cpp
  #include &lt;string&gt;
  #include &lt;iostream&gt;
  
  void *addr = NULL;
  
  class A
  {
  public:
      int i;
      int j;
  
  #if 0
      ~A() {}
  #endif
  };
  
  A fn()
  {
      A fn_a;
  
      addr = &amp;fn_a;
  
      return fn_a;
  }
  
  int main()
  {
      A a = fn();
  
      if (addr == &amp;a)
          std::cout &lt;&lt; &quot;Addresses match!\n&quot;;
      else
          std::cout &lt;&lt; &quot;Addresses do not match!\n&quot;;
  }
  </code></pre>
  <p>Notes:</p>
  <ol>
  <li><p>If a destructor is defined by enabling the <code>#if</code> above, then the NRVO does happen (and it also happens in some other cases such as defining a virtual method or adding a <code>std::string</code> member).</p>
  </li>
  <li><p>No methods have been defined so A is a POD struct, or in more recent terminology a <a href="https://stackoverflow.com/a/7189821/2319122">trivial class</a>.  I don't see an explicit exclusion for this in the above links.</p>
  </li>
  <li><p>Adding compiler optimisation (to a more complicated example that doesn't just reduce to the empty program!) doesn't make any difference.</p>
  </li>
  <li><p>Looking at the <a href="https://godbolt.org/z/f615xn" rel="nofollow noreferrer">assembly</a> for a second example shows that this even happens when I would expect mandatory Return Value Optimization (RVO), so the NRVO above was not prevented by taking the address of <code>fn_a</code> in <code>fn()</code>.  Clang, GCC, ICC and MSVC on x86-64 show the same behaviour suggesting this behaviour is intentional and not a bug in a specific compiler.</p>
  <pre><code> class A
   {
   public:
       int i;
       int j;
  
   #if 0
       ~A() {}
   #endif
   };
  
   A fn()
   {
       return A();
   }
  
   int main()
   {
       // Where NRVO occurs the call to fn() is preceded on x86-64 by a move
       // to RDI, otherwise it is followed by a move from RAX.
       A a = fn();
   }
  </code></pre>
  </li>
  </ol>