diff options
author | Eric Fiselier <eric@efcs.ca> | 2017-05-25 14:59:39 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2017-05-25 14:59:39 +0000 |
commit | fc50f62caafd35b3dd4297d7af109fb7e6c00675 (patch) | |
tree | b8f0eb8222ca57760c1363746a34757d601fcbdb /clang/lib/Sema/SemaCoroutine.cpp | |
parent | 4bf928282f0d4d3b4af92ba9e404a770d653c2df (diff) | |
download | bcm5719-llvm-fc50f62caafd35b3dd4297d7af109fb7e6c00675.tar.gz bcm5719-llvm-fc50f62caafd35b3dd4297d7af109fb7e6c00675.zip |
[coroutines] Diagnose when promise types fail to declare either return_void or return_value.
Summary:
According to the PDTS it's perfectly legal to have a promise type that defines neither `return_value` nor `return_void`. However a coroutine that uses such a promise type will almost always have UB, because it can never `co_return`.
This patch changes Clang to diagnose such cases as an error. It also cleans up some of the diagnostic messages relating to member lookup in the promise type.
Reviewers: GorNishanov, rsmith
Reviewed By: GorNishanov
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D33534
llvm-svn: 303868
Diffstat (limited to 'clang/lib/Sema/SemaCoroutine.cpp')
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 48 |
1 files changed, 37 insertions, 11 deletions
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 45b3a48d158..009380df0e1 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -23,14 +23,22 @@ using namespace clang; using namespace sema; -static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, - SourceLocation Loc) { +static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc, bool &Res) { DeclarationName DN = S.PP.getIdentifierInfo(Name); LookupResult LR(S, DN, Loc, Sema::LookupMemberName); // Suppress diagnostics when a private member is selected. The same warnings // will be produced again when building the call. LR.suppressDiagnostics(); - return S.LookupQualifiedName(LR, RD); + Res = S.LookupQualifiedName(LR, RD); + return LR; +} + +static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, + SourceLocation Loc) { + bool Res; + lookupMember(S, Name, RD, Loc, Res); + return Res; } /// Look up the std::coroutine_traits<...>::promise_type for the given @@ -861,9 +869,8 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); if (ReturnStmt.isInvalid()) { - S.Diag(Found.getFoundDecl()->getLocation(), - diag::note_promise_member_declared_here) - << DN.getAsString(); + S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here) + << DN; S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn.getFirstCoroutineStmtKeyword(); return false; @@ -993,13 +1000,32 @@ bool CoroutineStmtBuilder::makeOnFallthrough() { // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in // the scope of class P. If both are found, the program is ill-formed. - const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc); - const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc); + bool HasRVoid, HasRValue; + LookupResult LRVoid = + lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid); + LookupResult LRValue = + lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue); StmtResult Fallthrough; if (HasRVoid && HasRValue) { // FIXME Improve this diagnostic - S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed) + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_incompatible_return_functions) + << PromiseRecordDecl; + S.Diag(LRVoid.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRVoid.getLookupName(); + S.Diag(LRValue.getRepresentativeDecl()->getLocation(), + diag::note_member_first_declared_here) + << LRValue.getLookupName(); + return false; + } else if (!HasRVoid && !HasRValue) { + // FIXME: The PDTS currently specifies this case as UB, not ill-formed. + // However we still diagnose this as an error since until the PDTS is fixed. + S.Diag(FD.getLocation(), + diag::err_coroutine_promise_requires_return_function) + << PromiseRecordDecl; + S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) << PromiseRecordDecl; return false; } else if (HasRVoid) { @@ -1074,8 +1100,8 @@ bool CoroutineStmtBuilder::makeReturnObject() { static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) { if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) { auto *MethodDecl = MbrRef->getMethodDecl(); - S.Diag(MethodDecl->getLocation(), diag::note_promise_member_declared_here) - << MethodDecl->getName(); + S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here) + << MethodDecl; } S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn.getFirstCoroutineStmtKeyword(); |