Issue 91308
Summary Wrong type inference during recursive generic lambda
Labels new issue
Assignees
Reporter haruomaki
    Although the code below is quite complicated, it would be valid as C++20. g++ 13.2.1 accepts this code. But clang++ 18.0.0 fails, saying "return type of `self(n-2)` is `int`".

```c++
#include <iostream>
#include <map>

template <typename...>
struct LambdaTraits;

template <typename F>
struct LambdaTraits<F> : public LambdaTraits<decltype(&F::operator())> {};

template <typename F, typename... TArgs>
struct LambdaTraits<F, TArgs...> : LambdaTraits<decltype(&F::template operator()<TArgs...>)> {};

template <typename C, typename Ret, typename... Args>
struct LambdaTraits<Ret (C::*)(Args...) const> {
    using args_type = std::tuple<Args...>;
 using return_type = Ret;
};

struct Any {
    template <typename T>
    T operator()(T) const;
};

template <typename F>
struct MemoFix {
    F f;
    using Arg = std::tuple_element_t<1, typename LambdaTraits<F, Any>::args_type>;
    using Ret = LambdaTraits<F, Any>::return_type;
    std::map<Arg, Ret> cache{};

    Ret operator()(Arg x) {
        if (!cache.contains(x)) {
 cache[x] = f(std::ref(*this), x);
        }
        return cache[x];
    }
};

int main() {
    auto fibonacci = MemoFix{[&](auto self, int n) -> std::string {
        if (n <= 0) {
 return "0";
        }
        if (n == 1) {
 return "1";
        }

        std::string str = "(" + self(n - 2) + " + " + self(n - 1) + ")";
        return str;
    }};

 std::cout << fibonacci(5) << std::endl;
}
```

compile command ([godbolt](https://godbolt.org/z/bxc4sqzrs)): `clang++ -std=c++20 -g -Wall -Wextra main.cpp -o main && ./main`

outputs:
```
main.cpp:48:31: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]
   48 |         std::string str = "(" + self(n - 2) + " + " + self(n - 1) + ")";
      | ~~~~^~~~~~~~~~~~~
main.cpp:11:71: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<Any>' requested here
   11 | struct LambdaTraits<F, TArgs...> : LambdaTraits<decltype(&F::template operator()<TArgs...>)> {};
      | ^
main.cpp:27:50: note: in instantiation of template class 'LambdaTraits<(lambda at main.cpp:40:30), Any>' requested here
   27 | using Arg = std::tuple_element_t<1, typename LambdaTraits<F, Any>::args_type>;
      | ^
main.cpp:40:22: note: in instantiation of template class 'MemoFix<(lambda at main.cpp:40:30)>' requested here
   40 |     auto fibonacci = MemoFix{[&](auto self, int n) -> std::string {
      | ^
main.cpp:48:31: note: use array indexing to silence this warning
   48 |         std::string str = "(" + self(n - 2) + " + " + self(n - 1) + ")";
      |                               ^
      | &   [            ]
main.cpp:48:45: error: invalid operands to binary _expression_ ('const char *' and 'const char[4]')
   48 | std::string str = "(" + self(n - 2) + " + " + self(n - 1) + ")";
      |                           ~~~~~~~~~~~~~~~~~ ^ ~~~~~
1 warning and 1 error generated.
```

g++ compiles this code correctly. compile command ([godbolt](https://godbolt.org/z/Y1Gd53Pz5)): `g++ -std=c++20 -g -Wall -Wextra main.cpp -o main && ./main`

and outputs:
```
((1 + (0 + 1)) + ((0 + 1) + (1 + (0 + 1))))
```


# Details
This program displays the calculation process of the Fibonacci sequence.

- `LambdaTraits` is a metafunction that parses the received lambda type and returns the argument type and return value type.
- `MemoFix` is a class that combines a fixed point combinator and memoization using std::map.
- `F` is a lambda type.
- `Arg` should be deduced to `int`.
- `Ret` should be deduced to `std::string`.
- The `auto self` argument in the lambda _expression_ is actually a value of type MemoFix, so `self(n-2)` or `self(n-1)` should return a value of `std::string`.

However, for some reason, clang++ seems to incorrectly infer that the return value of `self(n-2)` is `int`.

Sorry for the complicated code; this bug only occurs when a lot of type inference is involved, so I think this is the minimal case. I hope someone can narrow down the problem more clearly.

Thanks!
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to