Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect promise constructor used with lambda coroutines #91983

Open
landelare opened this issue May 13, 2024 · 3 comments
Open

Incorrect promise constructor used with lambda coroutines #91983

landelare opened this issue May 13, 2024 · 3 comments
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" coroutines C++20 coroutines lambda C++11 lambda expressions

Comments

@landelare
Copy link

In the C++20 program below, the lambda has a non-static member operator(), but its object parameter is skipped when looking for a promise constructor overload. This results in the first overload being called, and an output of Wrong.

Tested on 18.1.5 and 19.0.0git (b5af667). When compiled with GCC or MSVC, the output is Correct, as expected.

Additionally, removing the second constructor should make the resulting program no longer compile, which is the case with MSVC and GCC, but not Clang.

#include <coroutine>
#include <iostream>

struct coro {};

struct promise {
    promise(int) {std::cout << "Wrong\n";}
    promise(auto, int){std::cout << "Correct\n";} // Remove me for an additional test case!

    coro get_return_object() {return {};}
    std::suspend_never initial_suspend() {return {};}
    std::suspend_never final_suspend() noexcept {return {};}
    void return_value(int) {}
    void unhandled_exception() {}
};

template<typename... T>
struct std::coroutine_traits<coro, T...> {
    using promise_type = promise;
};

int main() {
    int x = 0;
    [x](int y) -> coro { co_return x + y; }(1);
}
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" coroutines C++20 coroutines lambda C++11 lambda expressions and removed new issue labels May 13, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented May 13, 2024

@llvm/issue-subscribers-clang-frontend

Author: Laura Andelare (landelare)

In the C++20 program below, the lambda has a non-static member operator(), but its object parameter is skipped when looking for a promise constructor overload. This results in the first overload being called, and an output of `Wrong`.

Tested on 18.1.5 and 19.0.0git (b5af667). When compiled with GCC or MSVC, the output is Correct, as expected.

Additionally, removing the second constructor should make the resulting program no longer compile, which is the case with MSVC and GCC, but not Clang.

#include &lt;coroutine&gt;
#include &lt;iostream&gt;

struct coro {};

struct promise {
    promise(int) {std::cout &lt;&lt; "Wrong\n";}
    promise(auto, int){std::cout &lt;&lt; "Correct\n";} // Remove me for an additional test case!

    coro get_return_object() {return {};}
    std::suspend_never initial_suspend() {return {};}
    std::suspend_never final_suspend() noexcept {return {};}
    void return_value(int) {}
    void unhandled_exception() {}
};

template&lt;typename... T&gt;
struct std::coroutine_traits&lt;coro, T...&gt; {
    using promise_type = promise;
};

int main() {
    int x = 0;
    [x](int y) -&gt; coro { co_return x + y; }(1);
}

@llvmbot
Copy link
Collaborator

llvmbot commented May 13, 2024

@llvm/issue-subscribers-coroutines

Author: Laura Andelare (landelare)

In the C++20 program below, the lambda has a non-static member operator(), but its object parameter is skipped when looking for a promise constructor overload. This results in the first overload being called, and an output of `Wrong`.

Tested on 18.1.5 and 19.0.0git (b5af667). When compiled with GCC or MSVC, the output is Correct, as expected.

Additionally, removing the second constructor should make the resulting program no longer compile, which is the case with MSVC and GCC, but not Clang.

#include &lt;coroutine&gt;
#include &lt;iostream&gt;

struct coro {};

struct promise {
    promise(int) {std::cout &lt;&lt; "Wrong\n";}
    promise(auto, int){std::cout &lt;&lt; "Correct\n";} // Remove me for an additional test case!

    coro get_return_object() {return {};}
    std::suspend_never initial_suspend() {return {};}
    std::suspend_never final_suspend() noexcept {return {};}
    void return_value(int) {}
    void unhandled_exception() {}
};

template&lt;typename... T&gt;
struct std::coroutine_traits&lt;coro, T...&gt; {
    using promise_type = promise;
};

int main() {
    int x = 0;
    [x](int y) -&gt; coro { co_return x + y; }(1);
}

@ChuanqiXu9
Copy link
Member

It looks like this can be handled by #84519

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" coroutines C++20 coroutines lambda C++11 lambda expressions
Projects
Status: No status
Development

No branches or pull requests

4 participants