Author: Chuanqi Xu Date: 2025-09-05T14:58:05+08:00 New Revision: 60304161ce44c25dec7b87dd6a593d09eea5545a
URL: https://github.com/llvm/llvm-project/commit/60304161ce44c25dec7b87dd6a593d09eea5545a DIFF: https://github.com/llvm/llvm-project/commit/60304161ce44c25dec7b87dd6a593d09eea5545a.diff LOG: [C++20] [Modules] Add the abbrev number for coro-await-elidable calls The root cause of the issue is that we forgot to update the abbrev number correctly. The test would crash before. Added: clang/test/Modules/coro-await-elidable.cppm Modified: clang/lib/Serialization/ASTWriterStmt.cpp Removed: ################################################################################ diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e36d83fe4559b..dda81557cb22f 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -979,7 +979,8 @@ void ASTStmtWriter::VisitCallExpr(CallExpr *E) { Record.push_back(E->getFPFeatures().getAsOpaqueInt()); if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()) && - !E->usesMemberSyntax() && E->getStmtClass() == Stmt::CallExprClass) + !E->isCoroElideSafe() && !E->usesMemberSyntax() && + E->getStmtClass() == Stmt::CallExprClass) AbbrevToUse = Writer.getCallExprAbbrev(); Code = serialization::EXPR_CALL; @@ -1712,7 +1713,8 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { Record.push_back(E->getOperator()); Record.AddSourceLocation(E->BeginLoc); - if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind())) + if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()) && + !E->isCoroElideSafe() && !E->usesMemberSyntax()) AbbrevToUse = Writer.getCXXOperatorCallExprAbbrev(); Code = serialization::EXPR_CXX_OPERATOR_CALL; @@ -1721,7 +1723,8 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { void ASTStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { VisitCallExpr(E); - if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind())) + if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()) && + !E->isCoroElideSafe() && !E->usesMemberSyntax()) AbbrevToUse = Writer.getCXXMemberCallExprAbbrev(); Code = serialization::EXPR_CXX_MEMBER_CALL; diff --git a/clang/test/Modules/coro-await-elidable.cppm b/clang/test/Modules/coro-await-elidable.cppm new file mode 100644 index 0000000000000..2d635c6efa88b --- /dev/null +++ b/clang/test/Modules/coro-await-elidable.cppm @@ -0,0 +1,200 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 %t/task.cppm -I%t -emit-reduced-module-interface -o %t/task.pcm +// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/user.cpp -verify -fsyntax-only + +//--- coroutine.h + +namespace std { + +template <typename R, typename...> struct coroutine_traits { + using promise_type = typename R::promise_type; +}; + +template <typename Promise = void> struct coroutine_handle; + +template <> struct coroutine_handle<void> { + static coroutine_handle from_address(void *addr) noexcept { + coroutine_handle me; + me.ptr = addr; + return me; + } + void operator()() { resume(); } + void *address() const noexcept { return ptr; } + void resume() const { __builtin_coro_resume(ptr); } + void destroy() const { __builtin_coro_destroy(ptr); } + bool done() const { return __builtin_coro_done(ptr); } + coroutine_handle &operator=(decltype(nullptr)) { + ptr = nullptr; + return *this; + } + coroutine_handle(decltype(nullptr)) : ptr(nullptr) {} + coroutine_handle() : ptr(nullptr) {} +// void reset() { ptr = nullptr; } // add to P0057? + explicit operator bool() const { return ptr; } + +protected: + void *ptr; +}; + +template <typename Promise> struct coroutine_handle : coroutine_handle<> { + using coroutine_handle<>::operator=; + + static coroutine_handle from_address(void *addr) noexcept { + coroutine_handle me; + me.ptr = addr; + return me; + } + + Promise &promise() const { + return *reinterpret_cast<Promise *>( + __builtin_coro_promise(ptr, alignof(Promise), false)); + } + static coroutine_handle from_promise(Promise &promise) { + coroutine_handle p; + p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true); + return p; + } +}; + +template <typename _PromiseT> +bool operator==(coroutine_handle<_PromiseT> const &_Left, + coroutine_handle<_PromiseT> const &_Right) noexcept { + return _Left.address() == _Right.address(); +} + +template <typename _PromiseT> +bool operator!=(coroutine_handle<_PromiseT> const &_Left, + coroutine_handle<_PromiseT> const &_Right) noexcept { + return !(_Left == _Right); +} + +struct noop_coroutine_promise {}; + +template <> +struct coroutine_handle<noop_coroutine_promise> { + operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(address()); + } + + constexpr explicit operator bool() const noexcept { return true; } + constexpr bool done() const noexcept { return false; } + + constexpr void operator()() const noexcept {} + constexpr void resume() const noexcept {} + constexpr void destroy() const noexcept {} + + noop_coroutine_promise &promise() const noexcept { + return *static_cast<noop_coroutine_promise *>( + __builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false)); + } + + constexpr void *address() const noexcept { return __handle_; } + +private: + friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept; + + coroutine_handle() noexcept { + this->__handle_ = __builtin_coro_noop(); + } + + void *__handle_ = nullptr; +}; + +using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; + +inline noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); } + +struct suspend_always { + bool await_ready() noexcept { return false; } + void await_suspend(coroutine_handle<>) noexcept {} + void await_resume() noexcept {} +}; +struct suspend_never { + bool await_ready() noexcept { return true; } + void await_suspend(coroutine_handle<>) noexcept {} + void await_resume() noexcept {} +}; + +} // namespace std + +//--- task.cppm +module; +#include "coroutine.h" +export module task; +export template <typename T> +struct [[clang::coro_await_elidable]] Task { + struct promise_type { + struct FinalAwaiter { + bool await_ready() const noexcept { return false; } + + template <typename P> + std::coroutine_handle<> await_suspend(std::coroutine_handle<P> coro) noexcept { + if (!coro) + return std::noop_coroutine(); + return coro.promise().continuation; + } + void await_resume() noexcept {} + }; + + Task get_return_object() noexcept { + return std::coroutine_handle<promise_type>::from_promise(*this); + } + + std::suspend_always initial_suspend() noexcept { return {}; } + FinalAwaiter final_suspend() noexcept { return {}; } + void unhandled_exception() noexcept {} + void return_value(T x) noexcept { + value = x; + } + + std::coroutine_handle<> continuation; + T value; + }; + + Task(std::coroutine_handle<promise_type> handle) : handle(handle) {} + ~Task() { + if (handle) + handle.destroy(); + } + + struct Awaiter { + Awaiter(Task *t) : task(t) {} + bool await_ready() const noexcept { return false; } + void await_suspend(std::coroutine_handle<void> continuation) noexcept {} + T await_resume() noexcept { + return task->handle.promise().value; + } + + Task *task; + }; + + auto operator co_await() { + return Awaiter{this}; + } + +private: + std::coroutine_handle<promise_type> handle; +}; + +inline Task<int> callee() { + co_return 1; +} + +export inline Task<int> elidable() { + co_return co_await callee(); +} + +namespace std { + export using std::coroutine_traits; + export using std::coroutine_handle; + export using std::suspend_always; +} + +//--- user.cpp +// expected-no-diagnostics +import task; +Task<int> test() { + co_return co_await elidable(); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
