From 07ac63f89e4efb1916c3470700a91c6642b2c8c5 Mon Sep 17 00:00:00 2001 From: Gor Nishanov Date: Mon, 28 May 2018 18:08:47 +0000 Subject: [PATCH] [coroutines] Pass implicit object parameter to promise ctor (fix BUG37604) Summary: Complete the implementation of p0914r1. Implicit object parameter should be passed to a promise constructor. Fixes: https://bugs.llvm.org/show_bug.cgi?id=37604 Reviewers: modocache, rsmith, lewissbaker Reviewed By: modocache Subscribers: cfe-commits, EricWF Differential Revision: https://reviews.llvm.org/D47454 llvm-svn: 333379 --- clang/lib/Sema/SemaCoroutine.cpp | 14 +++++++++ clang/test/CodeGenCoroutines/coro-params.cpp | 25 +++++++++++++++ clang/test/SemaCXX/coroutines.cpp | 32 +++++++++++++++++--- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index aefea981e59f..c58172cabf9b 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -510,6 +510,20 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { // Build a list of arguments, based on the coroutine functions arguments, // that will be passed to the promise type's constructor. llvm::SmallVector CtorArgExprs; + + // Add implicit object parameter. + if (auto *MD = dyn_cast(FD)) { + if (MD->isInstance() && !isLambdaCallOperator(MD)) { + ExprResult ThisExpr = ActOnCXXThis(Loc); + if (ThisExpr.isInvalid()) + return nullptr; + ThisExpr = CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get()); + if (ThisExpr.isInvalid()) + return nullptr; + CtorArgExprs.push_back(ThisExpr.get()); + } + } + auto &Moves = ScopeInfo->CoroutineParameterMoves; for (auto *PD : FD->parameters()) { if (PD->getType()->isDependentType()) diff --git a/clang/test/CodeGenCoroutines/coro-params.cpp b/clang/test/CodeGenCoroutines/coro-params.cpp index 078d7eeb7bc6..d15286a52cb9 100644 --- a/clang/test/CodeGenCoroutines/coro-params.cpp +++ b/clang/test/CodeGenCoroutines/coro-params.cpp @@ -156,3 +156,28 @@ void coroutine_matching_promise_constructor(promise_matching_constructor, int, f // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits::promise_type"* %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]]) co_return; } + +struct some_class; + +struct method {}; + +template struct std::experimental::coroutine_traits { + struct promise_type { + promise_type(some_class&, float); + method get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); + }; +}; + +struct some_class { + method good_coroutine_calls_custom_constructor(float); +}; + +// CHECK-LABEL: define void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(%struct.some_class* +method some_class::good_coroutine_calls_custom_constructor(float) { + // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES3_f(%"struct.std::experimental::coroutine_traits::promise_type"* %__promise, %struct.some_class* dereferenceable(1) %{{.+}}, float + co_return; +} diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp index 0d0588dbbf00..b5f67045fa77 100644 --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -831,7 +831,7 @@ struct std::experimental::coroutine_traits { }; }; -extern "C" int f(mismatch_gro_type_tag1) { +extern "C" int f(mismatch_gro_type_tag1) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -848,7 +848,7 @@ struct std::experimental::coroutine_traits { }; }; -extern "C" int f(mismatch_gro_type_tag2) { +extern "C" int f(mismatch_gro_type_tag2) { // expected-error@-1 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -866,7 +866,7 @@ struct std::experimental::coroutine_traits { }; }; -extern "C" int f(mismatch_gro_type_tag3) { +extern "C" int f(mismatch_gro_type_tag3) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -885,7 +885,7 @@ struct std::experimental::coroutine_traits { }; }; -extern "C" int f(mismatch_gro_type_tag4) { +extern "C" int f(mismatch_gro_type_tag4) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -1246,7 +1246,10 @@ good_coroutine_calls_default_constructor() { co_return; } +struct some_class; + struct good_promise_custom_constructor { + good_promise_custom_constructor(some_class&, float, int); good_promise_custom_constructor(double, float, int); good_promise_custom_constructor() = delete; coro get_return_object(); @@ -1261,9 +1264,20 @@ good_coroutine_calls_custom_constructor(double, float, int) { co_return; } +struct some_class { + coro + good_coroutine_calls_custom_constructor(float, int) { + co_return; + } + coro + static good_coroutine_calls_custom_constructor(double, float, int) { + co_return; + } +}; + struct bad_promise_no_matching_constructor { bad_promise_no_matching_constructor(int, int, int); - // expected-note@+1 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}} + // expected-note@+1 2 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}} bad_promise_no_matching_constructor() = delete; coro get_return_object(); suspend_always initial_suspend(); @@ -1278,6 +1292,14 @@ bad_coroutine_calls_with_no_matching_constructor(int, int) { co_return; } +struct some_class2 { +coro +bad_coroutine_calls_with_no_matching_constructor(int, int, int) { + // expected-error@-1 {{call to deleted constructor}} + co_return; +} +}; + } // namespace CoroHandleMemberFunctionTest class awaitable_no_unused_warn {