diff options
author | Eric Fiselier <eric@efcs.ca> | 2017-04-03 19:21:00 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2017-04-03 19:21:00 +0000 |
commit | bee782bb9212180689062b28d578981516655498 (patch) | |
tree | 9d73081b74a67048ea134a0b83a053aad7a6c16d /clang/lib/Sema/SemaCoroutine.cpp | |
parent | dee5565869e00ef1fa62ea25c2f04c7d54b9e9fd (diff) | |
download | bcm5719-llvm-bee782bb9212180689062b28d578981516655498.tar.gz bcm5719-llvm-bee782bb9212180689062b28d578981516655498.zip |
[coroutines] Fix rebuilding of implicit and dependent coroutine statements.
Summary:
Certain implicitly generated coroutine statements, such as the calls to 'return_value()' or `return_void()` or `get_return_object_on_allocation_failure()`, cannot be built until the promise type is no longer dependent. This means they are not built until after the coroutine body statement has been transformed.
This patch fixes an issue where these statements would never be built for coroutine templates.
It also fixes a small issue where diagnostics about `get_return_object_on_allocation_failure()` were incorrectly suppressed.
Reviewers: rsmith, majnemer, GorNishanov, aaron.ballman
Reviewed By: GorNishanov
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D31487
llvm-svn: 299380
Diffstat (limited to 'clang/lib/Sema/SemaCoroutine.cpp')
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 128 |
1 files changed, 61 insertions, 67 deletions
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 14dd7cb7118..4a55e51495a 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -11,13 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "CoroutineStmtBuilder.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/SemaInternal.h" + using namespace clang; using namespace sema; @@ -683,47 +685,6 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, return OperatorDelete; } -namespace { -class SubStmtBuilder : public CoroutineBodyStmt::CtorArgs { - Sema &S; - FunctionDecl &FD; - FunctionScopeInfo &Fn; - bool IsValid; - SourceLocation Loc; - QualType RetType; - SmallVector<Stmt *, 4> ParamMovesVector; - const bool IsPromiseDependentType; - CXXRecordDecl *PromiseRecordDecl = nullptr; - -public: - SubStmtBuilder(Sema &S, FunctionDecl &FD, FunctionScopeInfo &Fn, Stmt *Body) - : S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()), - IsPromiseDependentType( - !Fn.CoroutinePromise || - Fn.CoroutinePromise->getType()->isDependentType()) { - this->Body = Body; - if (!IsPromiseDependentType) { - PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl(); - assert(PromiseRecordDecl && "Type should have already been checked"); - } - this->IsValid = makePromiseStmt() && makeInitialAndFinalSuspend() && - makeOnException() && makeOnFallthrough() && - makeReturnOnAllocFailure() && makeNewAndDeleteExpr() && - makeReturnObject() && makeParamMoves(); - } - - bool isInvalid() const { return !this->IsValid; } - - bool makePromiseStmt(); - bool makeInitialAndFinalSuspend(); - bool makeNewAndDeleteExpr(); - bool makeOnFallthrough(); - bool makeOnException(); - bool makeReturnObject(); - bool makeReturnOnAllocFailure(); - bool makeParamMoves(); -}; -} void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { FunctionScopeInfo *Fn = getCurFunction(); @@ -750,15 +711,47 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn->getFirstCoroutineStmtKeyword(); } - SubStmtBuilder Builder(*this, *FD, *Fn, Body); - if (Builder.isInvalid()) + CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body); + if (Builder.isInvalid() || !Builder.buildStatements()) return FD->setInvalidDecl(); // Build body for the coroutine wrapper statement. Body = CoroutineBodyStmt::Create(Context, Builder); } -bool SubStmtBuilder::makePromiseStmt() { +CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, + sema::FunctionScopeInfo &Fn, + Stmt *Body) + : S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()), + IsPromiseDependentType( + !Fn.CoroutinePromise || + Fn.CoroutinePromise->getType()->isDependentType()) { + this->Body = Body; + if (!IsPromiseDependentType) { + PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl(); + assert(PromiseRecordDecl && "Type should have already been checked"); + } + this->IsValid = makePromiseStmt() && makeInitialAndFinalSuspend(); +} + +bool CoroutineStmtBuilder::buildStatements() { + assert(this->IsValid && "coroutine already invalid"); + this->IsValid = makeReturnObject() && makeParamMoves(); + if (this->IsValid && !IsPromiseDependentType) + buildDependentStatements(); + return this->IsValid; +} + +bool CoroutineStmtBuilder::buildDependentStatements() { + assert(this->IsValid && "coroutine already invalid"); + assert(!this->IsPromiseDependentType && + "coroutine cannot have a dependent promise type"); + this->IsValid = makeOnException() && makeOnFallthrough() && + makeReturnOnAllocFailure() && makeNewAndDeleteExpr(); + return this->IsValid; +} + +bool CoroutineStmtBuilder::makePromiseStmt() { // Form a declaration statement for the promise declaration, so that AST // visitors can more easily find it. StmtResult PromiseStmt = @@ -770,7 +763,7 @@ bool SubStmtBuilder::makePromiseStmt() { return true; } -bool SubStmtBuilder::makeInitialAndFinalSuspend() { +bool CoroutineStmtBuilder::makeInitialAndFinalSuspend() { if (Fn.hasInvalidCoroutineSuspends()) return false; this->InitialSuspend = cast<Expr>(Fn.CoroutineSuspends.first); @@ -801,8 +794,9 @@ static bool diagReturnOnAllocFailure(Sema &S, Expr *E, return false; } -bool SubStmtBuilder::makeReturnOnAllocFailure() { - if (!PromiseRecordDecl) return true; +bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/8 // The unqualified-id get_return_object_on_allocation_failure is looked up in @@ -813,22 +807,22 @@ bool SubStmtBuilder::makeReturnOnAllocFailure() { DeclarationName DN = S.PP.getIdentifierInfo("get_return_object_on_allocation_failure"); LookupResult Found(S, DN, Loc, Sema::LookupMemberName); - // Suppress diagnostics when a private member is selected. The same warnings - // will be produced again when building the call. - Found.suppressDiagnostics(); - if (!S.LookupQualifiedName(Found, PromiseRecordDecl)) return true; + if (!S.LookupQualifiedName(Found, PromiseRecordDecl)) + return true; CXXScopeSpec SS; ExprResult DeclNameExpr = S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false); - if (DeclNameExpr.isInvalid()) return false; + if (DeclNameExpr.isInvalid()) + return false; if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn)) return false; ExprResult ReturnObjectOnAllocationFailure = S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc); - if (ReturnObjectOnAllocationFailure.isInvalid()) return false; + if (ReturnObjectOnAllocationFailure.isInvalid()) + return false; // FIXME: ActOnReturnStmt expects a scope that is inside of the function, due // to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); @@ -837,17 +831,18 @@ bool SubStmtBuilder::makeReturnOnAllocFailure() { // Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017) StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); - if (ReturnStmt.isInvalid()) return false; + if (ReturnStmt.isInvalid()) + return false; this->ReturnStmtOnAllocFailure = ReturnStmt.get(); return true; } -bool SubStmtBuilder::makeNewAndDeleteExpr() { +bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // Form and check allocation and deallocation calls. + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); QualType PromiseType = Fn.CoroutinePromise->getType(); - if (PromiseType->isDependentType()) - return true; if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type)) return false; @@ -920,9 +915,9 @@ bool SubStmtBuilder::makeNewAndDeleteExpr() { return true; } -bool SubStmtBuilder::makeOnFallthrough() { - if (!PromiseRecordDecl) - return true; +bool CoroutineStmtBuilder::makeOnFallthrough() { + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in @@ -951,11 +946,10 @@ bool SubStmtBuilder::makeOnFallthrough() { return true; } -bool SubStmtBuilder::makeOnException() { +bool CoroutineStmtBuilder::makeOnException() { // Try to form 'p.unhandled_exception();' - - if (!PromiseRecordDecl) - return true; + assert(!IsPromiseDependentType && + "cannot make statement while the promise type is dependent"); const bool RequireUnhandledException = S.getLangOpts().CXXExceptions; @@ -983,7 +977,7 @@ bool SubStmtBuilder::makeOnException() { return true; } -bool SubStmtBuilder::makeReturnObject() { +bool CoroutineStmtBuilder::makeReturnObject() { // Build implicit 'p.get_return_object()' expression and form initialization // of return type from it. @@ -1008,7 +1002,7 @@ bool SubStmtBuilder::makeReturnObject() { return true; } -bool SubStmtBuilder::makeParamMoves() { +bool CoroutineStmtBuilder::makeParamMoves() { // FIXME: Perform move-initialization of parameters into frame-local copies. return true; } |