Issue 129912
Summary Incorrect Clang compilation error in non-taken if-constexpr branch within template lambda
Labels clang
Assignees
Reporter mikebentley15
    Godbolt: https://godbolt.org/z/WGWWozG1q

The scenario is fairly strange to reproduce.  It's code to conditionally wrap a callable with a mutable or a const lambda.  The `if constexpr` branch that isn't taken causes the compilation to fail.

Simplified code:

```c++
#include <cstdio>
#include <iostream>
#include <type_traits>
#include <utility>

struct ConstWrap
{};
struct MutableWrap
{};

auto lambdaWrap(auto callable) -> decltype(auto)
{
    const auto decorator = [&callable]<typename WrapType>() {
        if constexpr (std::is_same_v<ConstWrap, WrapType>) {
            return [capturedCallable = std::move(callable)]() {
                std::puts("ConstWrap");
 capturedCallable();
            };
        } else {
 return [capturedCallable = std::move(callable)]() mutable {
 std::puts("MutableWrap");
                capturedCallable();
 };
        }
    };
    return decorator.template operator()<MutableWrap>();
}

int main()
{
    auto decorated =
 lambdaWrap([counter = 0]() mutable { std::cout << "Counter: " << ++counter << "\n"; });
    decorated();
    return 0;
}
```

This fails with

```
<source>:17:17: error: no matching function for call to object of type 'const typename std::remove_reference<(lambda at <source>:32:20) &>::type' (aka 'const (lambda at <source>:32:20)')
   17 | capturedCallable();
      | ^~~~~~~~~~~~~~~~
<source>:15:63: note: while substituting into a lambda _expression_ here
   15 |             return [capturedCallable = std::move(callable)]() {
      | ^
<source>:13:61: note: while substituting into a lambda _expression_ here
   13 |     const auto decorator = [&callable]<typename WrapType>() {
      | ^
<source>:32:9: note: in instantiation of function template specialization 'lambdaWrap<(lambda at <source>:32:20)>' requested here
   32 |         lambdaWrap([counter = 0]() mutable { std::cout << "Counter: " << ++counter << "\n"; });
      |         ^
<source>:32:20: note: candidate function not viable: 'this' argument has type 'const typename std::remove_reference<(lambda at <source>:32:20) &>::type' (aka 'const (lambda at <source>:32:20)'), but method is not marked const
   32 | lambdaWrap([counter = 0]() mutable { std::cout << "Counter: " << ++counter << "\n"; });
      |                    ^
1 error generated.
Compiler returned: 1
```

on Clang 18.1.0 and on trunk (same error).  This works if the `decorator` lambda is not within a templated function (e.g., move it into `main()` and it works).  My current workaround is to move the `if constexpr` outside of the `decorator`.

GCC 10.4 is capable of compiling this example.

Perhaps this is related to #113792.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to