summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2015-10-22 06:13:50 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2015-10-22 06:13:50 +0000
commitcfd53b4e999301c5d6c7785c34c49d4e952e8aa4 (patch)
treea3c42b906b543cb7d74e4c56eca187d6c594cdc3 /clang/lib
parentf8bdb0a9e47fef71d86bc48537d133256ca3d0ad (diff)
downloadbcm5719-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.cpp6
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp4
-rw-r--r--clang/lib/Parse/ParseStmt.cpp7
-rw-r--r--clang/lib/Sema/CMakeLists.txt1
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp106
-rw-r--r--clang/lib/Sema/SemaDecl.cpp3
-rw-r--r--clang/lib/Sema/SemaStmt.cpp26
-rw-r--r--clang/lib/Sema/TreeTransform.h4
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);
}
OpenPOWER on IntegriCloud