summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaCoroutine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaCoroutine.cpp')
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp118
1 files changed, 99 insertions, 19 deletions
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index c709a1a723d..be89cd16deb 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -373,7 +373,6 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
if (PromiseRef.isInvalid())
return ExprError();
- // Call 'yield_value', passing in E.
return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
}
@@ -780,7 +779,8 @@ bool CoroutineStmtBuilder::buildDependentStatements() {
assert(!this->IsPromiseDependentType &&
"coroutine cannot have a dependent promise type");
this->IsValid = makeOnException() && makeOnFallthrough() &&
- makeReturnOnAllocFailure() && makeNewAndDeleteExpr();
+ makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() &&
+ makeNewAndDeleteExpr();
return this->IsValid;
}
@@ -857,15 +857,16 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
if (ReturnObjectOnAllocationFailure.isInvalid())
return false;
- // FIXME: ActOnReturnStmt expects a scope that is inside of the function, due
- // to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
- // S.getCurScope()->getFnParent() == nullptr at ActOnFinishFunctionBody when
- // CoroutineBodyStmt is built. Figure it out and fix it.
- // Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017)
StmtResult ReturnStmt =
S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
- if (ReturnStmt.isInvalid())
+ if (ReturnStmt.isInvalid()) {
+ S.Diag(Found.getFoundDecl()->getLocation(),
+ diag::note_promise_member_declared_here)
+ << DN.getAsString();
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
return false;
+ }
this->ReturnStmtOnAllocFailure = ReturnStmt.get();
return true;
@@ -1047,27 +1048,106 @@ bool CoroutineStmtBuilder::makeOnException() {
}
bool CoroutineStmtBuilder::makeReturnObject() {
-
// Build implicit 'p.get_return_object()' expression and form initialization
// of return type from it.
ExprResult ReturnObject =
buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
if (ReturnObject.isInvalid())
return false;
- QualType RetType = FD.getReturnType();
- if (!RetType->isDependentType()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeResult(Loc, RetType, false);
- ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
- ReturnObject.get());
- if (ReturnObject.isInvalid())
+
+ this->ReturnValue = ReturnObject.get();
+ return true;
+}
+
+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(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+}
+
+bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+ assert(this->ReturnValue && "ReturnValue must be already formed");
+
+ QualType const GroType = this->ReturnValue->getType();
+ assert(!GroType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ QualType const FnRetType = FD.getReturnType();
+ assert(!FnRetType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ if (FnRetType->isVoidType()) {
+ ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc);
+ if (Res.isInvalid())
return false;
+
+ this->ResultDecl = Res.get();
+ return true;
}
- ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc);
- if (ReturnObject.isInvalid())
+
+ if (GroType->isVoidType()) {
+ // Trigger a nice error message.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeResult(Loc, FnRetType, false);
+ S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
return false;
+ }
- this->ReturnValue = ReturnObject.get();
+ auto *GroDecl = VarDecl::Create(
+ S.Context, &FD, FD.getLocation(), FD.getLocation(),
+ &S.PP.getIdentifierTable().get("__coro_gro"), GroType,
+ S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
+
+ S.CheckVariableDeclarationType(GroDecl);
+ if (GroDecl->isInvalidDecl())
+ return false;
+
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
+ ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
+ this->ReturnValue);
+ if (Res.isInvalid())
+ return false;
+
+ Res = S.ActOnFinishFullExpr(Res.get());
+ if (Res.isInvalid())
+ return false;
+
+ if (GroType == FnRetType) {
+ GroDecl->setNRVOVariable(true);
+ }
+
+ S.AddInitializerToDecl(GroDecl, Res.get(),
+ /*DirectInit=*/false);
+
+ S.FinalizeDeclaration(GroDecl);
+
+ // Form a declaration statement for the return declaration, so that AST
+ // visitors can more easily find it.
+ StmtResult GroDeclStmt =
+ S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
+ if (GroDeclStmt.isInvalid())
+ return false;
+
+ this->ResultDecl = GroDeclStmt.get();
+
+ ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
+ if (declRef.isInvalid())
+ return false;
+
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
+ if (ReturnStmt.isInvalid()) {
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
+ return false;
+ }
+
+ this->ReturnStmt = ReturnStmt.get();
return true;
}
OpenPOWER on IntegriCloud