diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-10-22 06:13:50 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-10-22 06:13:50 +0000 |
commit | cfd53b4e999301c5d6c7785c34c49d4e952e8aa4 (patch) | |
tree | a3c42b906b543cb7d74e4c56eca187d6c594cdc3 /clang/lib | |
parent | f8bdb0a9e47fef71d86bc48537d133256ca3d0ad (diff) | |
download | bcm5719-llvm-cfd53b4e999301c5d6c7785c34c49d4e952e8aa4.tar.gz bcm5719-llvm-cfd53b4e999301c5d6c7785c34c49d4e952e8aa4.zip |
[coroutines] Initial stub Sema functionality for handling coroutine await / yield / return.
llvm-svn: 250993
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 106 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 4 |
8 files changed, 142 insertions, 15 deletions
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 4b42a73dd24..f3316461ac0 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1045,10 +1045,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression - SourceLocation SavedLoc = ConsumeToken(); + SourceLocation CoawaitLoc = ConsumeToken(); Res = ParseCastExpression(false); - (void)SavedLoc; - // FIXME: Pass to Sema. + if (!Res.isInvalid()) + Res = Actions.ActOnCoawaitExpr(CoawaitLoc, Res.get()); return Res; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index c3df77300ca..bd9b9f97313 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1567,8 +1567,8 @@ ExprResult Parser::ParseCoyieldExpression() { SourceLocation Loc = ConsumeToken(); ExprResult Expr = ParseAssignmentExpression(); - (void)Loc; - // FIXME: Pass to Sema. + if (!Expr.isInvalid()) + Expr = Actions.ActOnCoyieldExpr(Loc, Expr.get()); return Expr; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 6ea8f4ec891..af7008f8e78 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1691,8 +1691,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRange) { - // FIXME: Pass CoawaitLoc to Sema. - ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.get(), + ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, + FirstPart.get(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), T.getCloseLocation(), @@ -1851,7 +1851,8 @@ StmtResult Parser::ParseReturnStatement() { return StmtError(); } } - // FIXME: Pass IsCoreturn to Sema. + if (IsCoreturn) + return Actions.ActOnCoreturnStmt(ReturnLoc, R.get()); return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope()); } diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 4a772d8972a..8aa005102fe 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangSema SemaChecking.cpp SemaCodeComplete.cpp SemaConsumer.cpp + SemaCoroutine.cpp SemaCUDA.cpp SemaDecl.cpp SemaDeclAttr.cpp diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp new file mode 100644 index 00000000000..6545b6709a2 --- /dev/null +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -0,0 +1,106 @@ +//===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ Coroutines. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +using namespace clang; +using namespace sema; + +static FunctionScopeInfo * +checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { + // 'co_await' and 'co_yield' are permitted in unevaluated operands. + if (S.isUnevaluatedContext()) + return nullptr; + + // Any other usage must be within a function. + auto *FD = dyn_cast<FunctionDecl>(S.CurContext); + if (!FD) { + S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) + ? diag::err_coroutine_objc_method + : diag::err_coroutine_outside_function) << Keyword; + } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) { + // Coroutines TS [special]/6: + // A special member function shall not be a coroutine. + // + // FIXME: We assume that this really means that a coroutine cannot + // be a constructor or destructor. + S.Diag(Loc, diag::err_coroutine_ctor_dtor) + << isa<CXXDestructorDecl>(FD) << Keyword; + } else if (FD->isConstexpr()) { + S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword; + } else if (FD->isVariadic()) { + S.Diag(Loc, diag::err_coroutine_varargs) << Keyword; + } else { + auto *ScopeInfo = S.getCurFunction(); + assert(ScopeInfo && "missing function scope for function"); + return ScopeInfo; + } + + return nullptr; +} + +ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) { + auto *Context = checkCoroutineContext(*this, Loc, "co_await"); + ExprResult Res = ExprError(); + + if (Context && !Res.isInvalid()) + Context->CoroutineStmts.push_back(Res.get()); + return Res; +} + +ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) { + auto *Context = checkCoroutineContext(*this, Loc, "co_yield"); + ExprResult Res = ExprError(); + + if (Context && !Res.isInvalid()) + Context->CoroutineStmts.push_back(Res.get()); + return Res; +} + +StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { + auto *Context = checkCoroutineContext(*this, Loc, "co_return"); + StmtResult Res = StmtError(); + + if (Context && !Res.isInvalid()) + Context->CoroutineStmts.push_back(Res.get()); + return Res; +} + +void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) { + FunctionScopeInfo *Fn = getCurFunction(); + assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine"); + + // Coroutines [stmt.return]p1: + // A return statement shall not appear in a coroutine. + if (!Fn->Returns.empty()) { + Diag(Fn->Returns.front()->getLocStart(), diag::err_return_in_coroutine); + auto *First = Fn->CoroutineStmts[0]; + Diag(First->getLocStart(), diag::note_declared_coroutine_here) + << 0; // FIXME: Indicate the kind here + } + + bool AnyCoawaits = false; + bool AnyCoyields = false; + for (auto *CoroutineStmt : Fn->CoroutineStmts) { + (void)CoroutineStmt; + AnyCoawaits = AnyCoyields = true; // FIXME + } + + if (!AnyCoawaits && !AnyCoyields) + Diag(Fn->CoroutineStmts.front()->getLocStart(), + diag::ext_coroutine_without_coawait_coyield); + + // FIXME: If we have a deduced return type, resolve it now. + // FIXME: Compute the promise type. + // FIXME: Perform analysis of initial and final suspend, and set_exception call. + // FIXME: Complete the semantic analysis of the CoroutineStmts. +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 174b9cf50f2..047ff152cf8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10907,6 +10907,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + if (getLangOpts().Coroutines && !getCurFunction()->CoroutineStmts.empty()) + CheckCompletedCoroutineBody(FD, Body); + if (FD) { FD->setBody(Body); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 0afff06f15d..fec12000950 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1924,7 +1924,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) { /// The body of the loop is not available yet, since it cannot be analysed until /// we have determined the type of the for-range-declaration. StmtResult -Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, +Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc, BuildForRangeKind Kind) { if (!First) @@ -1948,6 +1948,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, return StmtError(); } + // Coroutines: 'for co_await' implicitly co_awaits its range. + if (CoawaitLoc.isValid()) { + ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range); + if (Coawait.isInvalid()) return StmtError(); + Range = Coawait.get(); + } + // Build auto && __range = range-init SourceLocation RangeLoc = Range->getLocStart(); VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc, @@ -1969,7 +1976,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, return StmtError(); } - return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), + return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(), /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr, /*Inc=*/nullptr, DS, RParenLoc, Kind); } @@ -2063,6 +2070,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, /// and emit no diagnostics. static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, SourceLocation ForLoc, + SourceLocation CoawaitLoc, Stmt *LoopVarDecl, SourceLocation ColonLoc, Expr *Range, @@ -2079,7 +2087,7 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, return StmtResult(); StmtResult SR = - SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(), RParenLoc, Sema::BFRK_Check); if (SR.isInvalid()) @@ -2091,7 +2099,7 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, // case there are any other (non-fatal) problems with it. SemaRef.Diag(RangeLoc, diag::err_for_range_dereference) << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*"); - return SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + return SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild); } @@ -2114,7 +2122,8 @@ struct InvalidateOnErrorScope { /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult -Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, +Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, + SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind) { @@ -2244,6 +2253,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, // If building the range failed, try dereferencing the range expression // unless a diagnostic was issued or the end function is problematic. StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc, + CoawaitLoc, LoopVarDecl, ColonLoc, Range, RangeLoc, RParenLoc); @@ -2314,7 +2324,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, return StmtError(); IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); - IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); + if (!IncrExpr.isInvalid() && CoawaitLoc.isValid()) + IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get()); + if (!IncrExpr.isInvalid()) + IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { Diag(RangeLoc, diag::note_for_range_invalid_iterator) << RangeLoc << 2 << BeginRangeRef.get()->getType() ; @@ -2351,6 +2364,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (Kind == BFRK_Check) return StmtResult(); + // FIXME: Pass in CoawaitLoc in the dependent case. return new (Context) CXXForRangeStmt( RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(), IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, ColonLoc, RParenLoc); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 29073debcd7..117ae56969d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1737,7 +1737,9 @@ public: } } - return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, + SourceLocation CoawaitLoc; // FIXME + return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, + Range, BeginEnd, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); } |