title: Ill-formed goto jump in C++ with compile-time known-to-be-false condition: is it actually illegal?
body: <p>I am learning about some dark corners of C++ and, in particular, about the &quot;forbidden&quot; <code>goto</code> and some restrictions on its usage. This question is partially inspired by <a href="https://www.youtube.com/watch?v=KNqRjzSlUVo" rel="noreferrer">Patrice Roy's talk at CppCon 2019 &quot;Some Programming Myths Revisited&quot;</a> (<a href="https://youtu.be/KNqRjzSlUVo?list=PLDmhdaGQ9jF13KkiqpvE0LA0ioz8YV7SI&amp;t=634" rel="noreferrer">link to exact time with a similar example</a>).</p>
  <p>Note, this is a language lawyer question, and I in no way advocate for the usage of <code>goto</code> in this particular example.</p>
  <hr />
  <p>The following C++ code:</p>
  <pre class="lang-c++ prettyprint-override"><code>#include &lt;iostream&gt;
  #include &lt;cstdlib&gt;
  
  struct X {
      X() { std::cout&lt;&lt;&quot;X Constructor\n&quot;; }
      ~X() { std::cout&lt;&lt;&quot;X Destructor\n&quot;; }
  };
  
  bool maybe_skip() { return std::rand()%10 != 0; }
  
  int main()
  {
      if (maybe_skip()) goto here;
      
      X x; // has non-trivial constructor; thus, preventing jumping over itself
      here:
      
      return 0;
  }
  </code></pre>
  <p>is ill-formed and won't compile. Since <code>goto</code> can skip the initialization of <code>x</code> of type <code>X</code> that has a non-trivial constructor.</p>
  <p>Error message from Apple Clang:</p>
  <blockquote>
  <pre><code>error: cannot jump from this goto statement to its label
  if (maybe_skip()) goto here;
                    ^
  note: jump bypasses variable initialization
  X x;
    ^
  </code></pre>
  </blockquote>
  <p><strong>This is clear to me.</strong></p>
  <p>However, what is not clear, is why the variations of this with the <code>constexpr</code> qualifier</p>
  <pre><code>constexpr bool maybe_skip() { return false; }
  </code></pre>
  <p>or even simply going with an always <code>false</code> if-condition known in compile-time</p>
  <pre class="lang-c++ prettyprint-override"><code>#include &lt;iostream&gt;
  
  struct X {
      X() { std::cout&lt;&lt;&quot;X Constructor\n&quot;; }
      ~X() { std::cout&lt;&lt;&quot;X Destructor\n&quot;; }
  };
  
  constexpr bool maybe_skip() { return false; }  // actually cannot skip
  
  int main()
  {
      // if constexpr (maybe_skip()) goto here;
      if constexpr (false) goto here;
      
      X x; // has non-trivial constructor; thus, preventing jumping over itself
      here:
      
      return 0;
  }
  </code></pre>
  <p>is also ill-formed (tried on Apple Clang 11.0.3 and GCC 9.2).</p>
  <p>According to <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf" rel="noreferrer">Sec. 9.7 of N4713</a>:</p>
  <blockquote>
  <p>It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (11.6).</p>
  </blockquote>
  <p>So, <strong>does my second version</strong> of the program with <code>if constexpr (false) goto here;</code> <strong>actually &quot;jump&quot; in the eyes of the compiler</strong>, even though at the end of the day it would have deleted this &quot;jump&quot; anyway? <s>(<code>constexpr</code> in the last case with plain <code>false</code> is mostly redundant, but left for consistency)</s>.</p>
  <p>I might be missing the exact phrasing or interpretation of the standard, or the &quot;order of the operations&quot; because in my [apparently, faulty] logic, the illegal jump does not and cannot happen.</p>