| Issue |
177023
|
| Summary |
Enable `lifetimebound` analysis to go through `operator co_await` into `await_resume`
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
snarkmaster
|
Currently, `lifetimebound` analysis does not propagate through calls to `operator co_await`: https://godbolt.org/z/nnj6vnovx -- full code below. In short, imagine `Awaiter` that stores a reference, and correctly uses `lifetimebound` on its ctor and `await_resume`. Then:
```cpp
auto&& r1 = co_await Awaiter{tmp()}; // BAD: No warning!
auto&& r2 = Awaiter{tmp()}.await_resume(); // -Wdangling
```
The desired outcome is for both lines to emit `-Wdangling`.
Real-world user code looks like this, and hits an ASAN failure, which can be too little too late:
```cpp
auto temp = [] { return ResultT<std::string>{"will dangle"}; };
auto&& ref = co_await or_unwind(temp());
EXPECT_EQ("hello_dangling_test", ref); // ASAN: use-after-free
```
My questions:
- Is this a simple fix?
- If so, has anyone got the time and generosity to put up a PR?
- Or, if it's simple, but you don't have time for a PR, I *might* be able to take it on with the following pointers:
* What code & tests to change
* Any pitfalls
* Expected time for an experienced contributor to do commit this same PR (I'd just multiply my own time by 10x lol)
Thank you very much for any help with this!
```cpp
#include <coroutine>
#include <string>
struct Coro {
struct promise_type {
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
auto get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
};
std::coroutine_handle<promise_type> h;
Coro(std::coroutine_handle<promise_type> h) : h(h) {}
};
template <typename T>
struct Awaiter {
T&& ref;
explicit Awaiter(T&& r [[clang::lifetimebound]]) noexcept
: ref(static_cast<T&&>(r)) {}
bool await_ready() const noexcept { return true; }
void await_suspend(std::coroutine_handle<>) noexcept {}
// lifetimebound says: returned ref should not outlive `this`
T&& await_resume() const noexcept [[clang::lifetimebound]] {
return static_cast<T&&>(ref);
}
};
std::string tmp() { return "test"; }
Coro test_coro() {
[[maybe_unused]] auto&& r1 = co_await Awaiter{tmp()}; // BAD: No warning!
[[maybe_unused]] auto&& r2 = Awaiter{tmp()}.await_resume(); // -Wdangling
}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs