<div dir="ltr">Here is a really reduced example:<div><br></div><div>template<int I> auto foo() {</div><div>  if constexpr (I != 0)</div><div>    return 10;</div><div>  else</div><div>    return foo<1>();</div><div>}</div><div>int main() { return foo<0>(); }<br></div><div><br></div><div>gcc seems to apply [dcl.spec.auto]p9 wrongly, I think. It says:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed. Once a non-discarded return statement has been seen in a function, however, the return type deduced from that statement can be used in the rest of the function, including in other return statements.<br></blockquote><div><br></div><div>The key here is "Once a <b>non-discarded</b> return statement [...]". Here, `return 10;` is a discarded return statement and must be ignored for deduction, and so the first sentence applies to the last return statement. Note that if it weren't for if constexpr, that function would be well-formed.</div><div><br></div><div>Cheers,</div><div>Nicolas</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jan 4, 2018 at 6:18 PM, Christoph Siedentop via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><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="m_6211257430407456036gmail_signature"><br></div><div class="m_6211257430407456036gmail_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="m_6211257430407456036gmail_signature"><div class="m_6211257430407456036gmail_signature"><br></div><div class="m_6211257430407456036gmail_signature"><div class="m_6211257430407456036gmail_signature">// Compile with -std=c++17</div><div class="m_6211257430407456036gmail_signature">#include <functional></div><div class="m_6211257430407456036gmail_signature"><br></div><div class="m_6211257430407456036gmail_signature">template <typename F> decltype(auto) call(F &&f) {</div><div class="m_6211257430407456036gmail_signature"><br></div><div class="m_6211257430407456036gmail_signature">  // Match F to either f(), f(int) or f(int, int).</div><div class="m_6211257430407456036gmail_signature">  // Return            int, int(), or int(int, int)</div><div class="m_6211257430407456036gmail_signature">  if constexpr (std::is_invocable<F>::value) {</div><div class="m_6211257430407456036gmail_signature">    return f();</div><div class="m_6211257430407456036gmail_signature">  } else if constexpr (std::is_invocable<F, int>::value) {</div><div class="m_6211257430407456036gmail_signature">    auto b = [f]() { return f(3); };</div><div class="m_6211257430407456036gmail_signature">    return call(b);</div><div class="m_6211257430407456036gmail_signature">  } else {</div><div class="m_6211257430407456036gmail_signature">    // Note: Error in next line.</div><div class="m_6211257430407456036gmail_signature">    // If beginning replaced to read auto b = ..., it compiles on Clang.</div><div class="m_6211257430407456036gmail_signature">    std::function<int(int)> b = [f](int x) { return f(x, 2); };</div><div class="m_6211257430407456036gmail_signature">    return call(b);</div><div class="m_6211257430407456036gmail_signature">  }</div><div class="m_6211257430407456036gmail_signature">}</div><div class="m_6211257430407456036gmail_signature"><br></div><div class="m_6211257430407456036gmail_signature">int main() {</div><div class="m_6211257430407456036gmail_signature">  return call([](int x, int y) { return x * y; });</div><div class="m_6211257430407456036gmail_signature">}</div><div><br></div></div><div class="m_6211257430407456036gmail_signature"><div class="m_6211257430407456036gmail_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>         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~<wbr>~~~~~~~~~~~</div><div>2 errors generated.</div></div><div><br></div><div>Kind regards,</div><div>Christoph</div><div><br></div><div><br></div><div>------------------------------<wbr>-------</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>
<br>______________________________<wbr>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-dev</a><br>
<br></blockquote></div><br></div>