mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-09 17:43:57 +00:00
[Coroutines] Warning if return type of coroutine_handle::address is not void*
User can own a version of coroutine_handle::address() whose return type is not void* by using template specialization for coroutine_handle<> for some promise_type. In this case, the codes may violate the capability with existing async C APIs that accepted a void* data parameter which was then passed back to the user-provided callback. Patch by ChuanqiXu Differential Revision: https://reviews.llvm.org/D82442
This commit is contained in:
parent
a378c04495
commit
8849831d55
@ -10527,6 +10527,9 @@ def err_await_suspend_invalid_return_type : Error<
|
||||
def note_await_ready_no_bool_conversion : Note<
|
||||
"return type of 'await_ready' is required to be contextually convertible to 'bool'"
|
||||
>;
|
||||
def warn_coroutine_handle_address_invalid_return_type : Warning <
|
||||
"return type of 'coroutine_handle<>::address should be 'void*' (have %0) in order to get capability with existing async C API.">,
|
||||
InGroup<Coroutine>;
|
||||
def err_coroutine_promise_final_suspend_requires_nothrow : Error<
|
||||
"the expression 'co_await __promise.final_suspend()' is required to be non-throwing"
|
||||
>;
|
||||
|
@ -1751,6 +1751,7 @@ public:
|
||||
~InlinedRegionBodyRAII() { CGF.AllocaInsertPt = OldAllocaIP; }
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
/// CXXThisDecl - When generating code for a C++ member function,
|
||||
/// this will hold the implicit 'this' declaration.
|
||||
|
@ -391,7 +391,13 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
|
||||
return nullptr;
|
||||
|
||||
Expr *JustAddress = AddressExpr.get();
|
||||
// FIXME: Check that the type of AddressExpr is void*
|
||||
|
||||
// Check that the type of AddressExpr is void*
|
||||
if (!JustAddress->getType().getTypePtr()->isVoidPointerType())
|
||||
S.Diag(cast<CallExpr>(JustAddress)->getCalleeDecl()->getLocation(),
|
||||
diag::warn_coroutine_handle_address_invalid_return_type)
|
||||
<< JustAddress->getType();
|
||||
|
||||
return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
|
||||
JustAddress);
|
||||
}
|
||||
|
75
clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp
Normal file
75
clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// RUN: %clang_cc1 -verify %s -stdlib=libc++ -std=c++1z -fcoroutines-ts -fsyntax-only
|
||||
|
||||
namespace std::experimental {
|
||||
template <class Promise = void>
|
||||
struct coroutine_handle;
|
||||
|
||||
template <>
|
||||
struct coroutine_handle<void> {
|
||||
coroutine_handle() = default;
|
||||
static coroutine_handle from_address(void *) noexcept;
|
||||
void *address() const;
|
||||
};
|
||||
|
||||
template <class Promise>
|
||||
struct coroutine_handle : public coroutine_handle<> {
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
struct void_t_imp {
|
||||
using type = void;
|
||||
};
|
||||
template <class... Args>
|
||||
using void_t = typename void_t_imp<Args...>::type;
|
||||
|
||||
template <class T, class = void>
|
||||
struct traits_sfinae_base {};
|
||||
|
||||
template <class T>
|
||||
struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
|
||||
using promise_type = typename T::promise_type;
|
||||
};
|
||||
|
||||
template <class Ret, class... Args>
|
||||
struct coroutine_traits : public traits_sfinae_base<Ret> {};
|
||||
} // namespace std::experimental
|
||||
|
||||
struct suspend_never {
|
||||
bool await_ready() noexcept;
|
||||
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
|
||||
void await_resume() noexcept;
|
||||
};
|
||||
|
||||
struct task {
|
||||
struct promise_type {
|
||||
auto initial_suspend() { return suspend_never{}; }
|
||||
auto final_suspend() noexcept { return suspend_never{}; }
|
||||
auto get_return_object() { return task{}; }
|
||||
static void unhandled_exception() {}
|
||||
void return_void() {}
|
||||
};
|
||||
};
|
||||
|
||||
namespace std::experimental {
|
||||
template <>
|
||||
struct coroutine_handle<task::promise_type> : public coroutine_handle<> {
|
||||
coroutine_handle<task::promise_type> *address() const; // expected-warning {{return type of 'coroutine_handle<>::address should be 'void*'}}
|
||||
};
|
||||
} // namespace std::experimental
|
||||
|
||||
struct awaitable {
|
||||
bool await_ready();
|
||||
|
||||
std::experimental::coroutine_handle<task::promise_type>
|
||||
await_suspend(std::experimental::coroutine_handle<> handle);
|
||||
void await_resume();
|
||||
} a;
|
||||
|
||||
task f() {
|
||||
co_await a;
|
||||
}
|
||||
|
||||
int main() {
|
||||
f();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user