Skip to content

Commit

Permalink
[coroutine] Create coroutine body in the correct eval context (#78589)
Browse files Browse the repository at this point in the history
Fixes: #78290

See the bug for more context.
```cpp
Gen ACoroutine() {
  if constexpr (0) // remove it make clang compile.
    co_return;
  co_await Gen{};
}
```
We miss symbol of ctor of promise_type if the first coroutine statement
happens to be inside the disabled branch of `if constexpr`.

This happens because the promise object is built when we see the first
coroutine statement which is present in
`ExpressionEvaluationContext::DiscardedStatement` context due to `if
constexpr (0)`. This makes clang believe that the promise constructor is
only odr-used and not really "used".

The expr evaluation context for the coroutine body should not be related
to the context in which the first coroutine statement appears. We
override the context to `PotentiallyEvaluated`.

---------

Co-authored-by: cor3ntin <corentinjabot@gmail.com>
  • Loading branch information
usx95 and cor3ntin committed Jan 19, 2024
1 parent 461679f commit 498e1c2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,9 @@ Bug Fixes in This Version
Objective-C++ property accesses to not be converted to a function call
to the getter in the placement-args of new-expressions.
Fixes (`#65053 <https://github.com/llvm/llvm-project/issues/65053>`_)
- Fix an issue with missing symbol definitions when the first coroutine
statement appears in a discarded ``if constexpr`` branch.
Fixes (`#78290 <https://github.com/llvm/llvm-project/issues/78290>`_)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/ScopeInfo.h"
Expand Down Expand Up @@ -773,6 +774,9 @@ bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {

bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
StringRef Keyword) {
// Ignore previous expr evaluation contexts.
EnterExpressionEvaluationContext PotentiallyEvaluated(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
if (!checkCoroutineContext(*this, KWLoc, Keyword))
return false;
auto *ScopeInfo = getCurFunction();
Expand Down
34 changes: 34 additions & 0 deletions clang/test/SemaCXX/coroutine-promise-ctor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %clang_cc1 -std=c++20 -ast-dump %s | FileCheck %s
#include "Inputs/std-coroutine.h"

// Github issue: https://github.com/llvm/llvm-project/issues/78290
namespace GH78290 {
class Gen {
public:
class promise_type {
public:
template<typename... Args>
explicit promise_type(Args...) {}
// CHECK: CXXConstructorDecl {{.*}} used promise_type 'void ()' {{.*}}
// CHECK-NEXT: TemplateArgument pack
// CHECK-NEXT: CompoundStmt {{.*}}
Gen get_return_object() { return {}; }

void unhandled_exception() {}
void return_void() {}
std::suspend_always await_transform(Gen gen) { return {}; }

std::suspend_always initial_suspend() { return {}; }
// CHECK: CXXMethodDecl {{.*}} used initial_suspend {{.*}}
std::suspend_always final_suspend() noexcept { return {}; }
// CHECK: CXXMethodDecl {{.*}} used final_suspend {{.*}}
};
};

Gen CoroutineBody() {
if constexpr (0) {
co_await Gen{};
}
co_await Gen{};
}
} // namespace GH78290

0 comments on commit 498e1c2

Please sign in to comment.