[coroutines] Initial stub Sema functionality for handling coroutine await / yield / return.

llvm-svn: 250993
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 4a772d8..8aa0051 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -21,6 +21,7 @@
   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 0000000..6545b67
--- /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 174b9cf..047ff15 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10907,6 +10907,9 @@
   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 0afff06..fec1200 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1924,7 +1924,7 @@
 /// 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 @@
     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 @@
     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 @@
 /// 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 @@
       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 @@
   // 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 @@
 
 /// 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 @@
         // 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 @@
       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 @@
   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 29073deb..117ae56 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1737,7 +1737,9 @@
       }
     }
 
-    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);
   }