From: Eric Fiselier Date: Wed, 31 May 2017 23:41:11 +0000 (+0000) Subject: [coroutines] Fix checking for prvalue-ness of `await_suspend` return type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1cf6697b4406b7febeb4f9fdaa49ff494923505b;p=clang [coroutines] Fix checking for prvalue-ness of `await_suspend` return type Summary: @rsmith Does this correctly address the issues mentioned in https://reviews.llvm.org/D33625#inline-292971 ? Reviewers: rsmith, EricWF Reviewed By: EricWF Subscribers: cfe-commits, rsmith Differential Revision: https://reviews.llvm.org/D33636 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@304373 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 629e8b837f..4de4f47b8a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -8979,10 +8979,10 @@ def err_coroutine_promise_new_requires_nothrow : Error< def note_coroutine_promise_call_implicitly_required : Note< "call to %0 implicitly required by coroutine function here">; def err_await_suspend_invalid_return_type : Error< - "the return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)" + "return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)" >; def note_await_ready_no_bool_conversion : Note< - "the return type of 'await_ready' is required to be contextually convertible to 'bool'" + "return type of 'await_ready' is required to be contextually convertible to 'bool'" >; } diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index f5594bd64d..8a548c0ab8 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -391,8 +391,11 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, // [expr.await]p3 [...] // - await-suspend is the expression e.await_suspend(h), which shall be // a prvalue of type void or bool. - QualType RetType = AwaitSuspend->getType(); - if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) { + QualType RetType = AwaitSuspend->getCallReturnType(S.Context); + // non-class prvalues always have cv-unqualified types + QualType AdjRetType = RetType.getUnqualifiedType(); + if (RetType->isReferenceType() || + (AdjRetType != S.Context.BoolTy && AdjRetType != S.Context.VoidTy)) { S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), diag::err_await_suspend_invalid_return_type) << RetType; diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index 47ad86e5b0..a867cf68a6 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -840,12 +840,12 @@ coro no_return_value_or_return_void() { struct bad_await_suspend_return { bool await_ready(); - // expected-error@+1 {{the return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}} + // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}} char await_suspend(std::experimental::coroutine_handle<>); void await_resume(); }; struct bad_await_ready_return { - // expected-note@+1 {{the return type of 'await_ready' is required to be contextually convertible to 'bool'}} + // expected-note@+1 {{return type of 'await_ready' is required to be contextually convertible to 'bool'}} void await_ready(); bool await_suspend(std::experimental::coroutine_handle<>); void await_resume(); @@ -858,6 +858,14 @@ struct await_ready_explicit_bool { void await_suspend(std::experimental::coroutine_handle<>); void await_resume(); }; +template +struct await_suspend_type_test { + bool await_ready(); + // expected-error@+2 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &')}} + // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &&')}} + SuspendTy await_suspend(std::experimental::coroutine_handle<>); + void await_resume(); +}; void test_bad_suspend() { { // FIXME: The actual error emitted here is terrible, and no number of notes can save it. @@ -873,4 +881,14 @@ void test_bad_suspend() { await_ready_explicit_bool c; co_await c; // OK } + { + await_suspend_type_test a; + await_suspend_type_test b; + await_suspend_type_test c; + await_suspend_type_test d; + co_await a; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} + co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} + co_await c; // OK + co_await d; // OK + } }