<div dir="ltr">Dear Clang-Mailinglist,<div><br></div><div><div>I found some code which does compile on GCC (7.2) but fails to compile on Clang. Could you enlighten me, whether it should compile or not? It is using `if constexpr` to type match a template. </div><div><br></div><div>* Clang complains:  "function: '...' with deduced return type cannot be used before it is defined."</div><div>* GCC compiles this fine and main returns "6" as expected.<br></div><div>* I am using Clang from trunk.</div><div><br></div><div>Is Clang right in rejecting this code, or is GCC too permissive in accepting this? Could you let me know, why this is the case?</div><div class="gmail_signature"><br></div><div class="gmail_signature">Here is a minimal example, and the complete compile output for Clang. I also tried to reduce the example further with C-Reduce, but don't think the result aids understanding. </div><div class="gmail_signature"><div class="gmail_signature"><br></div><div class="gmail_signature"><div class="gmail_signature">// Compile with -std=c++17</div><div class="gmail_signature">#include <functional></div><div class="gmail_signature"><br></div><div class="gmail_signature">template <typename F> decltype(auto) call(F &&f) {</div><div class="gmail_signature"><br></div><div class="gmail_signature">  // Match F to either f(), f(int) or f(int, int).</div><div class="gmail_signature">  // Return            int, int(), or int(int, int)</div><div class="gmail_signature">  if constexpr (std::is_invocable<F>::value) {</div><div class="gmail_signature">    return f();</div><div class="gmail_signature">  } else if constexpr (std::is_invocable<F, int>::value) {</div><div class="gmail_signature">    auto b = [f]() { return f(3); };</div><div class="gmail_signature">    return call(b);</div><div class="gmail_signature">  } else {</div><div class="gmail_signature">    // Note: Error in next line.</div><div class="gmail_signature">    // If beginning replaced to read auto b = ..., it compiles on Clang.</div><div class="gmail_signature">    std::function<int(int)> b = [f](int x) { return f(x, 2); };</div><div class="gmail_signature">    return call(b);</div><div class="gmail_signature">  }</div><div class="gmail_signature">}</div><div class="gmail_signature"><br></div><div class="gmail_signature">int main() {</div><div class="gmail_signature">  return call([](int x, int y) { return x * y; });</div><div class="gmail_signature">}</div><div><br></div></div><div class="gmail_signature"><div class="gmail_signature"><div>Output: </div><div><div>bug5_manual.cc:17:12: error: function 'call<std::__1::function<int (int)> &>' with deduced return type cannot be used before it is defined</div><div>    return call(b);</div><div>           ^</div><div>bug5_manual.cc:4:38: note: 'call<std::__1::function<int (int)> &>' declared here</div><div>template <typename F> decltype(auto) call(F &&f) {</div><div>                                     ^</div><div>bug5_manual.cc:22:10: error: cannot initialize return object of type 'int' with an rvalue of type 'void'</div><div>  return call([](int x, int y) { return x * y; });</div><div>         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</div><div>2 errors generated.</div></div><div><br></div><div>Kind regards,</div><div>Christoph</div><div><br></div><div><br></div><div>-------------------------------------</div><div><br></div><div>PS: Here's the reduced code. As I said, I don't think it helps much.</div><div><div>template <typename c, c d> struct e { static constexpr c f = d; };</div><div>typedef e<bool, true> g;</div><div>struct h : g {};</div><div>template <typename> struct i : h {};</div><div>template <typename> class function;</div><div>template <typename j, typename... k> class function<j(k...)> {};</div><div>template <typename a> auto call(a) {</div><div>  if constexpr (i<int>::f)</div><div>    ;</div><div>  else {</div><div>    function<int()> b;</div><div>    call(b);</div><div>  }</div><div>}</div><div>main() {}</div></div><div><br></div><div>Reduced with the following script. For the reduction, I got the pre-processed code from GCC, the pre-processed code from Clang couldn't be compiled with GCC.</div><div><div>#!/bin/bash</div><div>set -e</div><div><br></div><div># Should continue to compile on GCC.</div><div>g++ -std=c++17 bug5.cc # NOTE: take care to use GCC 7.2 here.</div><div><br></div><div>clang++ -std=c++17 --compile bug5.cc 2>&1 \</div><div>| grep -q "with deduced return type cannot be used before it is defined" </div></div><div><br></div></div></div></div>
</div></div>