[cfe-dev] Template programming: std::function<> vs lambda not compiling on Clang but GCC.

Nicolas Lesser via cfe-dev cfe-dev at lists.llvm.org
Thu Jan 4 09:39:54 PST 2018


Here is a really reduced example:

template<int I> auto foo() {
  if constexpr (I != 0)
    return 10;
  else
    return foo<1>();
}
int main() { return foo<0>(); }

gcc seems to apply [dcl.spec.auto]p9 wrongly, I think. It says:

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.
>

The key here is "Once a *non-discarded* 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.

Cheers,
Nicolas

On Thu, Jan 4, 2018 at 6:18 PM, Christoph Siedentop via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Dear Clang-Mailinglist,
>
> 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.
>
> * Clang complains:  "function: '...' with deduced return type cannot be
> used before it is defined."
> * GCC compiles this fine and main returns "6" as expected.
> * I am using Clang from trunk.
>
> 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?
>
> 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.
>
> // Compile with -std=c++17
> #include <functional>
>
> template <typename F> decltype(auto) call(F &&f) {
>
>   // Match F to either f(), f(int) or f(int, int).
>   // Return            int, int(), or int(int, int)
>   if constexpr (std::is_invocable<F>::value) {
>     return f();
>   } else if constexpr (std::is_invocable<F, int>::value) {
>     auto b = [f]() { return f(3); };
>     return call(b);
>   } else {
>     // Note: Error in next line.
>     // If beginning replaced to read auto b = ..., it compiles on Clang.
>     std::function<int(int)> b = [f](int x) { return f(x, 2); };
>     return call(b);
>   }
> }
>
> int main() {
>   return call([](int x, int y) { return x * y; });
> }
>
> Output:
> bug5_manual.cc:17:12: error: function 'call<std::__1::function<int (int)>
> &>' with deduced return type cannot be used before it is defined
>     return call(b);
>            ^
> bug5_manual.cc:4:38: note: 'call<std::__1::function<int (int)> &>'
> declared here
> template <typename F> decltype(auto) call(F &&f) {
>                                      ^
> bug5_manual.cc:22:10: error: cannot initialize return object of type 'int'
> with an rvalue of type 'void'
>   return call([](int x, int y) { return x * y; });
>          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 2 errors generated.
>
> Kind regards,
> Christoph
>
>
> -------------------------------------
>
> PS: Here's the reduced code. As I said, I don't think it helps much.
> template <typename c, c d> struct e { static constexpr c f = d; };
> typedef e<bool, true> g;
> struct h : g {};
> template <typename> struct i : h {};
> template <typename> class function;
> template <typename j, typename... k> class function<j(k...)> {};
> template <typename a> auto call(a) {
>   if constexpr (i<int>::f)
>     ;
>   else {
>     function<int()> b;
>     call(b);
>   }
> }
> main() {}
>
> 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.
> #!/bin/bash
> set -e
>
> # Should continue to compile on GCC.
> g++ -std=c++17 bug5.cc # NOTE: take care to use GCC 7.2 here.
>
> clang++ -std=c++17 --compile bug5.cc 2>&1 \
> | grep -q "with deduced return type cannot be used before it is defined"
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180104/f0972dfc/attachment.html>


More information about the cfe-dev mailing list