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

[coroutine] Create coroutine body in the correct eval context #78589

Merged
merged 6 commits into from
Jan 19, 2024

Conversation

usx95
Copy link
Contributor

@usx95 usx95 commented Jan 18, 2024

Fixes: #78290

See the bug for more context.

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.

@usx95 usx95 added the coroutines C++20 coroutines label Jan 18, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 18, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 18, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-coroutines

Author: Utkarsh Saxena (usx95)

Changes

Fixes: #78290

See the bug for more context.

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.


Full diff: https://github.com/llvm/llvm-project/pull/78589.diff

2 Files Affected:

  • (modified) clang/lib/Sema/SemaCoroutine.cpp (+4)
  • (added) clang/test/SemaCXX/coroutine-promise-ctor.cpp (+34)
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 0e0f8f67dcd73e..4e600fd29ee739 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -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"
@@ -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();
diff --git a/clang/test/SemaCXX/coroutine-promise-ctor.cpp b/clang/test/SemaCXX/coroutine-promise-ctor.cpp
new file mode 100644
index 00000000000000..c8a976e838241f
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-promise-ctor.cpp
@@ -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
+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{};
+}
+
+int main() { return 0; }
\ No newline at end of file

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a release note for this change (mentioning the issue) ? thanks!

clang/test/SemaCXX/coroutine-promise-ctor.cpp Outdated Show resolved Hide resolved
@usx95
Copy link
Contributor Author

usx95 commented Jan 18, 2024

Added release notes and fix new line.

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!
Please give a chance to @ChuanqiXu9 to look at it before merging

clang/docs/ReleaseNotes.rst Outdated Show resolved Hide resolved
Co-authored-by: cor3ntin <corentinjabot@gmail.com>
Copy link
Collaborator

@hokein hokein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, this looks good to me.

clang/test/SemaCXX/coroutine-promise-ctor.cpp Outdated Show resolved Hide resolved
clang/test/SemaCXX/coroutine-promise-ctor.cpp Show resolved Hide resolved
Copy link
Member

@ChuanqiXu9 ChuanqiXu9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks.

@usx95 usx95 merged commit 498e1c2 into llvm:main Jan 19, 2024
4 of 5 checks passed
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" clang Clang issues not falling into any other category coroutines C++20 coroutines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

link error when compiling coroutine code.
5 participants