r251387 - [coroutines] Creation of promise object, lookup of operator co_await, building

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 26 23:02:46 PDT 2015


Author: rsmith
Date: Tue Oct 27 01:02:45 2015
New Revision: 251387

URL: http://llvm.org/viewvc/llvm-project?rev=251387&view=rev
Log:
[coroutines] Creation of promise object, lookup of operator co_await, building
of await_* calls, and AST representation for same.

Modified:
    cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/OperationKinds.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/StmtCXX.h
    cfe/trunk/include/clang/AST/StmtVisitor.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/StmtNodes.td
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/StmtCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/ScopeInfo.cpp
    cfe/trunk/lib/Sema/SemaCoroutine.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/Parser/cxx1z-coroutines.cpp
    cfe/trunk/test/SemaCXX/coroutines.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Tue Oct 27 01:02:45 2015
@@ -43,7 +43,7 @@
   OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec)        \
       OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus)          \
       OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag)               \
-      OPERATOR(Extension)
+      OPERATOR(Extension) OPERATOR(Coawait)
 
 // All binary operators (excluding compound assign operators).
 #define BINOP_LIST()                                                           \
@@ -2306,6 +2306,12 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryEx
 DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
 
+// Coroutine support.
+DEF_TRAVERSE_STMT(CoroutineBodyStmt, {})
+DEF_TRAVERSE_STMT(CoreturnStmt, {})
+DEF_TRAVERSE_STMT(CoawaitExpr, {})
+DEF_TRAVERSE_STMT(CoyieldExpr, {})
+
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, {})
 DEF_TRAVERSE_STMT(CharacterLiteral, {})

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Oct 27 01:02:45 2015
@@ -4008,6 +4008,129 @@ public:
   child_range children() { return child_range(SubExprs, SubExprs + 2); }
 };
 
+/// \brief Represents a 'co_await' expression. This expression checks whether its
+/// operand is ready, and suspends the coroutine if not. Then (after the resume
+/// if suspended) it resumes the coroutine and extracts the value from the
+/// operand. This implies making four calls:
+///
+///   <operand>.operator co_await() or operator co_await(<operand>)
+///   <result>.await_ready()
+///   <result>.await_suspend(h)
+///   <result>.await_resume()
+///
+/// where h is a handle to the coroutine, and <result> is the result of calling
+/// operator co_await() if it exists or the original operand otherwise.
+///
+/// Note that the coroutine is prepared for suspension before the 'await_suspend'
+/// call, but resumes after that call, which may cause parts of the
+/// 'await_suspend' expression to occur much later than expected.
+class CoawaitExpr : public Expr {
+  SourceLocation CoawaitLoc;
+
+  enum SubExpr { Operand, Ready, Suspend, Resume, Count };
+  Stmt *SubExprs[SubExpr::Count];
+
+  friend class ASTStmtReader;
+public:
+  CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
+              Expr *Suspend, Expr *Resume)
+      : Expr(CoawaitExprClass, Resume->getType(), Resume->getValueKind(),
+             Resume->getObjectKind(),
+             Resume->isTypeDependent(),
+             Resume->isValueDependent(),
+             Operand->isInstantiationDependent(),
+             Operand->containsUnexpandedParameterPack()),
+      CoawaitLoc(CoawaitLoc),
+      SubExprs{Operand, Ready, Suspend, Resume} {}
+  CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
+      : Expr(CoawaitExprClass, Ty, VK_RValue, OK_Ordinary,
+             true, true, true, Operand->containsUnexpandedParameterPack()),
+        CoawaitLoc(CoawaitLoc), SubExprs{Operand} {
+    assert(Operand->isTypeDependent() && Ty->isDependentType() &&
+           "wrong constructor for non-dependent co_await expression");
+  }
+  CoawaitExpr(EmptyShell Empty) : Expr(CoawaitExprClass, Empty) {}
+
+  SourceLocation getKeywordLoc() const { return CoawaitLoc; }
+  Expr *getOperand() const {
+    return static_cast<Expr*>(SubExprs[SubExpr::Operand]);
+  }
+
+  Expr *getReadyExpr() const {
+    return static_cast<Expr*>(SubExprs[SubExpr::Ready]);
+  }
+  Expr *getSuspendExpr() const {
+    return static_cast<Expr*>(SubExprs[SubExpr::Suspend]);
+  }
+  Expr *getResumeExpr() const {
+    return static_cast<Expr*>(SubExprs[SubExpr::Resume]);
+  }
+
+  SourceLocation getLocStart() const LLVM_READONLY {
+    return CoawaitLoc;
+  }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return getOperand()->getLocEnd();
+  }
+
+  child_range children() {
+    return child_range(SubExprs, SubExprs + SubExpr::Count);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CoawaitExprClass;
+  }
+};
+
+/// \brief Represents a 'co_yield' expression. This expression provides a value
+/// to the coroutine promise and optionally suspends the coroutine. This implies
+/// a making call to <promise>.yield_value(<operand>), which we name the "promise
+/// call".
+class CoyieldExpr : public Expr {
+  SourceLocation CoyieldLoc;
+
+  /// The operand of the 'co_yield' expression.
+  Stmt *Operand;
+  /// The implied call to the promise object. May be null if the
+  /// coroutine has not yet been finalized.
+  Stmt *PromiseCall;
+
+  friend class ASTStmtReader;
+public:
+  CoyieldExpr(SourceLocation CoyieldLoc, QualType Void, Expr *Operand)
+      : Expr(CoyieldExprClass, Void, VK_RValue, OK_Ordinary, false, false,
+             Operand->isInstantiationDependent(),
+             Operand->containsUnexpandedParameterPack()),
+        CoyieldLoc(CoyieldLoc), Operand(Operand), PromiseCall(nullptr) {}
+  CoyieldExpr(EmptyShell Empty) : Expr(CoyieldExprClass, Empty) {}
+
+  SourceLocation getKeywordLoc() const { return CoyieldLoc; }
+  Expr *getOperand() const { return static_cast<Expr*>(Operand); }
+
+  /// \brief Get the call to the promise objet that is implied by an evaluation
+  /// of this expression. Will be nullptr if the coroutine has not yet been
+  /// finalized.
+  Expr *getPromiseCall() const { return static_cast<Expr*>(PromiseCall); }
+
+  /// \brief Set the resolved promise call. This is delayed until the
+  /// complete coroutine body has been parsed and the promise type is known.
+  void finalize(Stmt *PC) { PromiseCall = PC; }
+
+  SourceLocation getLocStart() const LLVM_READONLY { return CoyieldLoc; }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return Operand->getLocEnd();
+  }
+
+  child_range children() {
+    Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
+    return child_range(Which, Which + 1);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CoyieldExprClass;
+  }
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/OperationKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OperationKinds.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OperationKinds.h (original)
+++ cfe/trunk/include/clang/AST/OperationKinds.h Tue Oct 27 01:02:45 2015
@@ -334,7 +334,8 @@ enum UnaryOperatorKind {
   UO_Plus, UO_Minus,      // [C99 6.5.3.3] Unary arithmetic
   UO_Not, UO_LNot,        // [C99 6.5.3.3] Unary arithmetic
   UO_Real, UO_Imag,       // "__real expr"/"__imag expr" Extension.
-  UO_Extension            // __extension__ marker.
+  UO_Extension,           // __extension__ marker.
+  UO_Coawait              // [C++ Coroutines] co_await operator
 };
 
 /// \brief The kind of bridging performed by the Objective-C bridge cast.

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct 27 01:02:45 2015
@@ -43,7 +43,7 @@
   OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec)        \
       OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus)          \
       OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag)               \
-      OPERATOR(Extension)
+      OPERATOR(Extension) OPERATOR(Coawait)
 
 // All binary operators (excluding compound assign operators).
 #define BINOP_LIST()                                                           \
@@ -2346,6 +2346,34 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryEx
 DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
 
+// For coroutines expressions, traverse either the operand
+// as written or the implied calls, depending on what the
+// derived class requests.
+DEF_TRAVERSE_STMT(CoroutineBodyStmt, {
+  if (!getDerived().shouldVisitImplicitCode()) {
+    TRY_TO(TraverseStmt(S->getBody()));
+    return true;
+  }
+})
+DEF_TRAVERSE_STMT(CoreturnStmt, {
+  if (!getDerived().shouldVisitImplicitCode()) {
+    TRY_TO(TraverseStmt(S->getOperand()));
+    return true;
+  }
+})
+DEF_TRAVERSE_STMT(CoawaitExpr, {
+  if (!getDerived().shouldVisitImplicitCode()) {
+    TRY_TO(TraverseStmt(S->getOperand()));
+    return true;
+  }
+})
+DEF_TRAVERSE_STMT(CoyieldExpr, {
+  if (!getDerived().shouldVisitImplicitCode()) {
+    TRY_TO(TraverseStmt(S->getOperand()));
+    return true;
+  }
+})
+
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, {})
 DEF_TRAVERSE_STMT(CharacterLiteral, {})

Modified: cfe/trunk/include/clang/AST/StmtCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtCXX.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtCXX.h (original)
+++ cfe/trunk/include/clang/AST/StmtCXX.h Tue Oct 27 01:02:45 2015
@@ -131,12 +131,16 @@ class CXXForRangeStmt : public Stmt {
   // SubExprs[RANGE] is an expression or declstmt.
   // SubExprs[COND] and SubExprs[INC] are expressions.
   Stmt *SubExprs[END];
+  SourceLocation CoawaitLoc;
   SourceLocation ColonLoc;
   SourceLocation RParenLoc;
+
+  friend class ASTStmtReader;
 public:
   CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
                   Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
-                  SourceLocation FL, SourceLocation CL, SourceLocation RPL);
+                  SourceLocation FL, SourceLocation CAL, SourceLocation CL,
+                  SourceLocation RPL);
   CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
 
 
@@ -181,13 +185,10 @@ public:
   void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
   void setBody(Stmt *S) { SubExprs[BODY] = S; }
 
-
   SourceLocation getForLoc() const { return ForLoc; }
-  void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
+  SourceLocation getCoawaitLoc() const { return CoawaitLoc; }
   SourceLocation getColonLoc() const { return ColonLoc; }
-  void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
-  void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
 
   SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; }
   SourceLocation getLocEnd() const LLVM_READONLY {
@@ -287,6 +288,95 @@ public:
   }
 };
 
+/// \brief Represents the body of a coroutine. This wraps the normal function
+/// body and holds the additional semantic context required to set up and tear
+/// down the coroutine frame.
+class CoroutineBodyStmt : public Stmt {
+  enum SubStmt { Body, Count };
+  Stmt *SubStmts[SubStmt::Count];
+
+  friend class ASTStmtReader;
+public:
+  CoroutineBodyStmt(Stmt *Body)
+      : Stmt(CoroutineBodyStmtClass), SubStmts{Body} {}
+
+  /// \brief Retrieve the body of the coroutine as written. This will be either
+  /// a CompoundStmt or a TryStmt.
+  Stmt *getBody() const {
+    return SubStmts[SubStmt::Body];
+  }
+
+  SourceLocation getLocStart() const LLVM_READONLY {
+    return getBody()->getLocStart();
+  }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return getBody()->getLocEnd();
+  }
+
+  child_range children() {
+    return child_range(SubStmts, SubStmts + SubStmt::Count);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CoroutineBodyStmtClass;
+  }
+};
+
+/// \brief Represents a 'co_return' statement in the C++ Coroutines TS.
+///
+/// This statament models the initialization of the coroutine promise
+/// (encapsulating the eventual notional return value) from an expression
+/// (or braced-init-list).
+///
+/// This initialization is modeled by a call to one of:
+///   <promise>.return_value(<operand>)
+///   <promise>.return_void()
+/// which we name the "promise call".
+class CoreturnStmt : public Stmt {
+  SourceLocation CoreturnLoc;
+
+  /// The operand of the 'co_return' statement.
+  Stmt *Operand;
+  /// The implied call to the promise object. May be null if the
+  /// coroutine has not yet been finalized.
+  Stmt *PromiseCall;
+
+  friend class ASTStmtReader;
+public:
+  CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand)
+      : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
+        Operand(Operand), PromiseCall(nullptr) {}
+
+  SourceLocation getKeywordLoc() const { return CoreturnLoc; }
+
+  /// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
+  /// if none was specified.
+  Expr *getOperand() const { return static_cast<Expr*>(Operand); }
+
+  /// \brief Retrieve the promise call that results from this 'co_return'
+  /// statement. Will be nullptr if either the coroutine has not yet been
+  /// finalized or the coroutine has no eventual return type.
+  Expr *getPromiseCall() const { return static_cast<Expr*>(PromiseCall); }
+
+  /// \brief Set the resolved promise call. This is delayed until the
+  /// complete coroutine body has been parsed and the promise type is known.
+  void finalize(Stmt *PC) { PromiseCall = PC; }
+
+  SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return Operand->getLocEnd();
+  }
+
+  child_range children() {
+    Stmt **Which = PromiseCall ? &PromiseCall : &Operand;
+    return child_range(Which, Which + 1);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CoreturnStmtClass;
+  }
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/StmtVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtVisitor.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtVisitor.h (original)
+++ cfe/trunk/include/clang/AST/StmtVisitor.h Tue Oct 27 01:02:45 2015
@@ -94,6 +94,7 @@ public:
       case UO_Real:      DISPATCH(UnaryReal,      UnaryOperator);
       case UO_Imag:      DISPATCH(UnaryImag,      UnaryOperator);
       case UO_Extension: DISPATCH(UnaryExtension, UnaryOperator);
+      case UO_Coawait:   DISPATCH(UnaryCoawait,   UnaryOperator);
       }
     }
 
@@ -158,7 +159,7 @@ public:
   UNARYOP_FALLBACK(Plus)      UNARYOP_FALLBACK(Minus)
   UNARYOP_FALLBACK(Not)       UNARYOP_FALLBACK(LNot)
   UNARYOP_FALLBACK(Real)      UNARYOP_FALLBACK(Imag)
-  UNARYOP_FALLBACK(Extension)
+  UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(Coawait)
 #undef UNARYOP_FALLBACK
 
   // Base case, ignore it. :)

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 27 01:02:45 2015
@@ -7839,7 +7839,8 @@ def err_module_import_in_implementation
 }
 
 let CategoryName = "Coroutines Issue" in {
-def err_return_in_coroutine : Error<"return statement in coroutine">;
+def err_return_in_coroutine : Error<
+  "return statement not allowed in coroutine; did you mean 'co_return'?">;
 def note_declared_coroutine_here : Note<
   "function is a coroutine due to use of "
   "'%select{co_await|co_yield|co_return}0' here">;
@@ -7853,10 +7854,24 @@ def err_coroutine_constexpr : Error<
   "'%0' cannot be used in a constexpr function">;
 def err_coroutine_varargs : Error<
   "'%0' cannot be used in a varargs function">;
-def ext_coroutine_without_coawait_coyield : ExtWarn<
+def ext_coroutine_without_co_await_co_yield : ExtWarn<
   "'co_return' used in a function "
   "that uses neither 'co_await' nor 'co_yield'">,
   InGroup<DiagGroup<"coreturn-without-coawait">>;
+def err_co_await_no_viable_function : Error<
+  "invalid co_await operand of type %0; "
+  "no viable '%1' function %select{|for awaited type %3 }2available">;
+def err_implied_std_coroutine_traits_not_found : Error<
+  "you need to include <coroutine> before defining a coroutine">;
+def err_malformed_std_coroutine_traits : Error<
+  "std::coroutine_traits must be a class template">;
+def err_implied_std_coroutine_traits_promise_type_not_found : Error<
+  "this function cannot be a coroutine: %0 has no member named 'promise_type'">;
+def err_implied_std_coroutine_traits_promise_type_not_class : Error<
+  "this function cannot be a coroutine: %0 is not a class">;
+def err_coroutine_traits_missing_specialization : Error<
+  "this function cannot be a coroutine: missing definition of "
+  "specialization %0">;
 }
 
 let CategoryName = "Documentation Issue" in {

Modified: cfe/trunk/include/clang/Basic/StmtNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
+++ cfe/trunk/include/clang/Basic/StmtNodes.td Tue Oct 27 01:02:45 2015
@@ -48,6 +48,10 @@ def CXXCatchStmt : Stmt;
 def CXXTryStmt : Stmt;
 def CXXForRangeStmt : Stmt;
 
+// C++ Coroutines TS statements
+def CoroutineBodyStmt : Stmt;
+def CoreturnStmt : Stmt;
+
 // Expressions
 def Expr : Stmt<1>;
 def PredefinedExpr : DStmt<Expr>;
@@ -140,6 +144,10 @@ def MaterializeTemporaryExpr : DStmt<Exp
 def LambdaExpr : DStmt<Expr>;
 def CXXFoldExpr : DStmt<Expr>;
 
+// C++ Coroutines TS expressions
+def CoawaitExpr : DStmt<Expr>;
+def CoyieldExpr : DStmt<Expr>;
+
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
 def ObjCBoxedExpr : DStmt<Expr>;

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Tue Oct 27 01:02:45 2015
@@ -89,40 +89,43 @@ protected:
 public:
   /// \brief What kind of scope we are describing.
   ///
-  ScopeKind Kind;
+  ScopeKind Kind : 2;
 
   /// \brief Whether this function contains a VLA, \@try, try, C++
   /// initializer, or anything else that can't be jumped past.
-  bool HasBranchProtectedScope;
+  bool HasBranchProtectedScope : 1;
 
   /// \brief Whether this function contains any switches or direct gotos.
-  bool HasBranchIntoScope;
+  bool HasBranchIntoScope : 1;
 
   /// \brief Whether this function contains any indirect gotos.
-  bool HasIndirectGoto;
+  bool HasIndirectGoto : 1;
 
   /// \brief Whether a statement was dropped because it was invalid.
-  bool HasDroppedStmt;
+  bool HasDroppedStmt : 1;
 
   /// A flag that is set when parsing a method that must call super's
   /// implementation, such as \c -dealloc, \c -finalize, or any method marked
   /// with \c __attribute__((objc_requires_super)).
-  bool ObjCShouldCallSuper;
+  bool ObjCShouldCallSuper : 1;
 
   /// True when this is a method marked as a designated initializer.
-  bool ObjCIsDesignatedInit;
+  bool ObjCIsDesignatedInit : 1;
   /// This starts true for a method marked as designated initializer and will
   /// be set to false if there is an invocation to a designated initializer of
   /// the super class.
-  bool ObjCWarnForNoDesignatedInitChain;
+  bool ObjCWarnForNoDesignatedInitChain : 1;
 
   /// True when this is an initializer method not marked as a designated
   /// initializer within a class that has at least one initializer marked as a
   /// designated initializer.
-  bool ObjCIsSecondaryInit;
+  bool ObjCIsSecondaryInit : 1;
   /// This starts true for a secondary initializer method and will be set to
   /// false if there is an invocation of an initializer on 'self'.
-  bool ObjCWarnForNoInitDelegation;
+  bool ObjCWarnForNoInitDelegation : 1;
+
+  /// First 'return' statement in the current function.
+  SourceLocation FirstReturnLoc;
 
   /// First C++ 'try' statement in the current function.
   SourceLocation FirstCXXTryLoc;
@@ -142,6 +145,9 @@ public:
   /// optimization, or if we need to infer a return type.
   SmallVector<ReturnStmt*, 4> Returns;
 
+  /// \brief The promise object for this coroutine, if any.
+  VarDecl *CoroutinePromise;
+
   /// \brief The list of coroutine control flow constructs (co_await, co_yield,
   /// co_return) that occur within the function or block. Empty if and only if
   /// this function or block is not (yet known to be) a coroutine.

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 27 01:02:45 2015
@@ -2492,17 +2492,8 @@ public:
     FRS_DiagnosticIssued
   };
 
-  // An enum to represent whether something is dealing with a call to begin()
-  // or a call to end() in a range-based for loop.
-  enum BeginEndFunction {
-    BEF_begin,
-    BEF_end
-  };
-
-  ForRangeStatus BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
+  ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc,
                                            SourceLocation RangeLoc,
-                                           VarDecl *Decl,
-                                           BeginEndFunction BEF,
                                            const DeclarationNameInfo &NameInfo,
                                            LookupResult &MemberLookup,
                                            OverloadCandidateSet *CandidateSet,
@@ -3324,7 +3315,7 @@ public:
     BFRK_Check
   };
 
-  StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc,
+  StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
                                   SourceLocation CoawaitLoc,
                                   Stmt *LoopVar,
                                   SourceLocation ColonLoc, Expr *Collection,
@@ -7699,10 +7690,14 @@ public:
   //===--------------------------------------------------------------------===//
   // C++ Coroutines TS
   //
-  ExprResult ActOnCoawaitExpr(SourceLocation KwLoc, Expr *E);
-  ExprResult ActOnCoyieldExpr(SourceLocation KwLoc, Expr *E);
+  ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
+  ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
   StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E);
 
+  ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E);
+  ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E);
+  StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E);
+
   void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body);
 
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Oct 27 01:02:45 2015
@@ -4915,13 +4915,14 @@ Stmt *ASTNodeImporter::VisitCXXForRangeS
   if (!ToBody && S->getBody())
     return nullptr;
   SourceLocation ToForLoc = Importer.Import(S->getForLoc());
+  SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
   SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
   SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
   return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd,
                                                        ToCond, ToInc,
                                                        ToLoopVar, ToBody,
-                                                       ToForLoc, ToColonLoc,
-                                                       ToRParenLoc);
+                                                       ToForLoc, ToCoawaitLoc,
+                                                       ToColonLoc, ToRParenLoc);
 }
 
 Stmt *ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 27 01:02:45 2015
@@ -1079,6 +1079,7 @@ StringRef UnaryOperator::getOpcodeStr(Op
   case UO_Real:    return "__real";
   case UO_Imag:    return "__imag";
   case UO_Extension: return "__extension__";
+  case UO_Coawait: return "co_await";
   }
   llvm_unreachable("Unknown unary operator");
 }
@@ -1095,6 +1096,7 @@ UnaryOperator::getOverloadedOpcode(Overl
   case OO_Minus:      return UO_Minus;
   case OO_Tilde:      return UO_Not;
   case OO_Exclaim:    return UO_LNot;
+  case OO_Coawait:    return UO_Coawait;
   }
 }
 
@@ -1108,6 +1110,7 @@ OverloadedOperatorKind UnaryOperator::ge
   case UO_Minus: return OO_Minus;
   case UO_Not: return OO_Tilde;
   case UO_LNot: return OO_Exclaim;
+  case UO_Coawait: return OO_Coawait;
   default: return OO_None;
   }
 }
@@ -2050,6 +2053,9 @@ bool Expr::isUnusedResultAWarning(const
     case UO_LNot:
     case UO_Deref:
       break;
+    case UO_Coawait:
+      // This is just the 'operator co_await' call inside the guts of a
+      // dependent co_await call.
     case UO_PostInc:
     case UO_PostDec:
     case UO_PreInc:
@@ -3005,6 +3011,8 @@ bool Expr::HasSideEffects(const ASTConte
   case CXXNewExprClass:
   case CXXDeleteExprClass:
   case ExprWithCleanupsClass:
+  case CoawaitExprClass:
+  case CoyieldExprClass:
     // These always have a side-effect.
     return true;
 

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Tue Oct 27 01:02:45 2015
@@ -186,6 +186,7 @@ static Cl::Kinds ClassifyInternal(ASTCon
   case Expr::CXXFoldExprClass:
   case Expr::NoInitExprClass:
   case Expr::DesignatedInitUpdateExprClass:
+  case Expr::CoyieldExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
@@ -397,6 +398,9 @@ static Cl::Kinds ClassifyInternal(ASTCon
     assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
            "Only 1-element init lists can be glvalues.");
     return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
+
+  case Expr::CoawaitExprClass:
+    return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
   }
 
   llvm_unreachable("unhandled expression kind in classification");

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Oct 27 01:02:45 2015
@@ -9017,6 +9017,8 @@ static ICEDiag CheckICE(const Expr* E, c
   case Expr::AtomicExprClass:
   case Expr::LambdaExprClass:
   case Expr::CXXFoldExprClass:
+  case Expr::CoawaitExprClass:
+  case Expr::CoyieldExprClass:
     return ICEDiag(IK_NotICE, E->getLocStart());
 
   case Expr::InitListExprClass: {
@@ -9102,6 +9104,7 @@ static ICEDiag CheckICE(const Expr* E, c
     case UO_PreDec:
     case UO_AddrOf:
     case UO_Deref:
+    case UO_Coawait:
       // C99 6.6/3 allows increment and decrement within unevaluated
       // subexpressions of constant expressions, but they can never be ICEs
       // because an ICE cannot contain an lvalue operand.

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Oct 27 01:02:45 2015
@@ -3514,6 +3514,18 @@ recurse:
   case Expr::CXXThisExprClass:
     Out << "fpT";
     break;
+
+  case Expr::CoawaitExprClass:
+    // FIXME: Propose a non-vendor mangling.
+    Out << "v18co_await";
+    mangleExpression(cast<CoawaitExpr>(E)->getOperand());
+    break;
+
+  case Expr::CoyieldExprClass:
+    // FIXME: Propose a non-vendor mangling.
+    Out << "v18co_yield";
+    mangleExpression(cast<CoawaitExpr>(E)->getOperand());
+    break;
   }
 }
 

Modified: cfe/trunk/lib/AST/StmtCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtCXX.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtCXX.cpp (original)
+++ cfe/trunk/lib/AST/StmtCXX.cpp Tue Oct 27 01:02:45 2015
@@ -52,8 +52,10 @@ CXXTryStmt::CXXTryStmt(SourceLocation tr
 CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
                                  Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
                                  Stmt *Body, SourceLocation FL,
-                                 SourceLocation CL, SourceLocation RPL)
-    : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
+                                 SourceLocation CAL, SourceLocation CL,
+                                 SourceLocation RPL)
+    : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
+      RParenLoc(RPL) {
   SubExprs[RANGE] = Range;
   SubExprs[BEGINEND] = BeginEndStmt;
   SubExprs[COND] = Cond;

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Oct 27 01:02:45 2015
@@ -2163,6 +2163,31 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFo
   OS << ")";
 }
 
+// C++ Coroutines TS
+
+void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+  Visit(S->getBody());
+}
+
+void StmtPrinter::VisitCoreturnStmt(CoreturnStmt *S) {
+  OS << "co_return";
+  if (S->getOperand()) {
+    OS << " ";
+    Visit(S->getOperand());
+  }
+  OS << ";";
+}
+
+void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
+  OS << "co_await ";
+  PrintExpr(S->getOperand());
+}
+
+void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) {
+  OS << "co_yield ";
+  PrintExpr(S->getOperand());
+}
+
 // Obj-C
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Oct 27 01:02:45 2015
@@ -1362,6 +1362,22 @@ void StmtProfiler::VisitCXXFoldExpr(cons
   ID.AddInteger(S->getOperator());
 }
 
+void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitCoreturnStmt(const CoreturnStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) {
+  VisitExpr(S);
+}
+
+void StmtProfiler::VisitCoyieldExpr(const CoyieldExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
   VisitExpr(E);  
 }

Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Tue Oct 27 01:02:45 2015
@@ -445,6 +445,7 @@ til::SExpr *SExprBuilder::translateUnary
   case UO_Real:
   case UO_Imag:
   case UO_Extension:
+  case UO_Coawait:
     return new (Arena) til::Undefined(UO);
   }
   return new (Arena) til::Undefined(UO);

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Tue Oct 27 01:02:45 2015
@@ -141,6 +141,10 @@ void CodeGenFunction::EmitStmt(const Stm
   case Stmt::SwitchStmtClass:   EmitSwitchStmt(cast<SwitchStmt>(*S));     break;
   case Stmt::GCCAsmStmtClass:   // Intentional fall-through.
   case Stmt::MSAsmStmtClass:    EmitAsmStmt(cast<AsmStmt>(*S));           break;
+  case Stmt::CoroutineBodyStmtClass:
+  case Stmt::CoreturnStmtClass:
+    CGM.ErrorUnsupported(S, "coroutine");
+    break;
   case Stmt::CapturedStmtClass: {
     const CapturedStmt *CS = cast<CapturedStmt>(S);
     EmitCapturedStmt(*CS, CS->getCapturedRegionKind());

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Oct 27 01:02:45 2015
@@ -1048,7 +1048,7 @@ ExprResult Parser::ParseCastExpression(b
     SourceLocation CoawaitLoc = ConsumeToken();
     Res = ParseCastExpression(false);
     if (!Res.isInvalid())
-      Res = Actions.ActOnCoawaitExpr(CoawaitLoc, Res.get());
+      Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get());
     return Res;
   }
 

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Oct 27 01:02:45 2015
@@ -1568,7 +1568,7 @@ ExprResult Parser::ParseCoyieldExpressio
   SourceLocation Loc = ConsumeToken();
   ExprResult Expr = ParseAssignmentExpression();
   if (!Expr.isInvalid())
-    Expr = Actions.ActOnCoyieldExpr(Loc, Expr.get());
+    Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get());
   return Expr;
 }
 

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Oct 27 01:02:45 2015
@@ -1691,13 +1691,10 @@ StmtResult Parser::ParseForStatement(Sou
   StmtResult ForEachStmt;
 
   if (ForRange) {
-    ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc,
-                                                FirstPart.get(),
-                                                ForRangeInit.ColonLoc,
-                                                ForRangeInit.RangeExpr.get(),
-                                                T.getCloseLocation(),
-                                                Sema::BFRK_Build);
-
+    ForRangeStmt = Actions.ActOnCXXForRangeStmt(
+        getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
+        ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(),
+        T.getCloseLocation(), Sema::BFRK_Build);
 
   // Similarly, we need to do the semantic analysis for a for-range
   // statement immediately in order to close over temporaries correctly.

Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Tue Oct 27 01:02:45 2015
@@ -33,11 +33,13 @@ void FunctionScopeInfo::Clear() {
   ObjCWarnForNoDesignatedInitChain = false;
   ObjCIsSecondaryInit = false;
   ObjCWarnForNoInitDelegation = false;
+  FirstReturnLoc = SourceLocation();
   FirstCXXTryLoc = SourceLocation();
   FirstSEHTryLoc = SourceLocation();
 
   SwitchStack.clear();
   Returns.clear();
+  CoroutineStmts.clear();
   ErrorTrap.reset();
   PossiblyUnreachableDiags.clear();
   WeakObjectUses.clear();

Modified: cfe/trunk/lib/Sema/SemaCoroutine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCoroutine.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCoroutine.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCoroutine.cpp Tue Oct 27 01:02:45 2015
@@ -12,12 +12,89 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Overload.h"
 using namespace clang;
 using namespace sema;
 
+/// Look up the std::coroutine_traits<...>::promise_type for the given
+/// function type.
+static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
+                                  SourceLocation Loc) {
+  // FIXME: Cache std::coroutine_traits once we've found it.
+  NamespaceDecl *Std = S.getStdNamespace();
+  if (!Std) {
+    S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+    return QualType();
+  }
+
+  LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
+                      Loc, Sema::LookupOrdinaryName);
+  if (!S.LookupQualifiedName(Result, Std)) {
+    S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+    return QualType();
+  }
+
+  ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
+  if (!CoroTraits) {
+    Result.suppressDiagnostics();
+    // We found something weird. Complain about the first thing we found.
+    NamedDecl *Found = *Result.begin();
+    S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
+    return QualType();
+  }
+
+  // Form template argument list for coroutine_traits<R, P1, P2, ...>.
+  TemplateArgumentListInfo Args(Loc, Loc);
+  Args.addArgument(TemplateArgumentLoc(
+      TemplateArgument(FnType->getReturnType()),
+      S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
+  for (QualType T : FnType->getParamTypes())
+    Args.addArgument(TemplateArgumentLoc(
+        TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
+
+  // Build the template-id.
+  QualType CoroTrait =
+      S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args);
+  if (CoroTrait.isNull())
+    return QualType();
+  if (S.RequireCompleteType(Loc, CoroTrait,
+                            diag::err_coroutine_traits_missing_specialization))
+    return QualType();
+
+  CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl();
+  assert(RD && "specialization of class template is not a class?");
+
+  // Look up the ::promise_type member.
+  LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc,
+                 Sema::LookupOrdinaryName);
+  S.LookupQualifiedName(R, RD);
+  auto *Promise = R.getAsSingle<TypeDecl>();
+  if (!Promise) {
+    S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found)
+      << RD;
+    return QualType();
+  }
+
+  // The promise type is required to be a class type.
+  QualType PromiseType = S.Context.getTypeDeclType(Promise);
+  if (!PromiseType->getAsCXXRecordDecl()) {
+    S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
+      << PromiseType;
+    return QualType();
+  }
+
+  return PromiseType;
+}
+
+/// Check that this is a context in which a coroutine suspension can appear.
 static FunctionScopeInfo *
 checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
   // 'co_await' and 'co_yield' are permitted in unevaluated operands.
+  // FIXME: Not in 'noexcept'.
   if (S.isUnevaluatedContext())
     return nullptr;
 
@@ -42,36 +119,143 @@ checkCoroutineContext(Sema &S, SourceLoc
   } else {
     auto *ScopeInfo = S.getCurFunction();
     assert(ScopeInfo && "missing function scope for function");
+
+    // If we don't have a promise variable, build one now.
+    if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) {
+      QualType T =
+          lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc);
+      if (T.isNull())
+        return nullptr;
+
+      // Create and default-initialize the promise.
+      ScopeInfo->CoroutinePromise =
+          VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
+                          &S.PP.getIdentifierTable().get("__promise"), T,
+                          S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
+      S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
+      if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
+        S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false);
+    }
+
     return ScopeInfo;
   }
 
   return nullptr;
 }
 
-ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) {
-  auto *Context = checkCoroutineContext(*this, Loc, "co_await");
-  ExprResult Res = ExprError();
+/// Build a call to 'operator co_await' if there is a suitable operator for
+/// the given expression.
+static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
+                                           SourceLocation Loc, Expr *E) {
+  UnresolvedSet<16> Functions;
+  SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
+                                       Functions);
+  return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
+}
+
+struct ReadySuspendResumeResult {
+  bool IsInvalid;
+  Expr *Results[3];
+};
+
+/// Build calls to await_ready, await_suspend, and await_resume for a co_await
+/// expression.
+static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
+                                                  Expr *E) {
+  // Assume invalid until we see otherwise.
+  ReadySuspendResumeResult Calls = {true, {}};
+
+  const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
+  for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
+    DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc);
+
+    Expr *Operand = new (S.Context) OpaqueValueExpr(
+        Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E);
+
+    // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
+    CXXScopeSpec SS;
+    ExprResult Result = S.BuildMemberReferenceExpr(
+        Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS,
+        SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
+        /*Scope=*/nullptr);
+    if (Result.isInvalid())
+      return Calls;
+
+    // FIXME: Pass coroutine handle to await_suspend.
+    Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr);
+    if (Result.isInvalid())
+      return Calls;
+    Calls.Results[I] = Result.get();
+  }
+
+  Calls.IsInvalid = false;
+  return Calls;
+}
+
+ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
+  ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+  if (Awaitable.isInvalid())
+    return ExprError();
+  return BuildCoawaitExpr(Loc, Awaitable.get());
+}
+ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
+  auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
 
-  if (Context && !Res.isInvalid())
-    Context->CoroutineStmts.push_back(Res.get());
+  if (E->getType()->isDependentType()) {
+    Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
+    if (Coroutine)
+      Coroutine->CoroutineStmts.push_back(Res);
+    return Res;
+  }
+
+  if (E->getType()->isPlaceholderType()) {
+    ExprResult R = CheckPlaceholderExpr(E);
+    if (R.isInvalid()) return ExprError();
+    E = R.get();
+  }
+
+  // FIXME: If E is a prvalue, create a temporary.
+  // FIXME: If E is an xvalue, convert to lvalue.
+
+  // Build the await_ready, await_suspend, await_resume calls.
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
+  if (RSS.IsInvalid)
+    return ExprError();
+
+  Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+                                        RSS.Results[2]);
+  if (Coroutine)
+    Coroutine->CoroutineStmts.push_back(Res);
   return Res;
 }
 
-ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) {
-  auto *Context = checkCoroutineContext(*this, Loc, "co_yield");
-  ExprResult Res = ExprError();
+ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
+  // FIXME: Build yield_value call.
+  ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+  if (Awaitable.isInvalid())
+    return ExprError();
+  return BuildCoyieldExpr(Loc, Awaitable.get());
+}
+ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
+  auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
 
-  if (Context && !Res.isInvalid())
-    Context->CoroutineStmts.push_back(Res.get());
+  // FIXME: Build await_* calls.
+  Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E);
+  if (Coroutine)
+    Coroutine->CoroutineStmts.push_back(Res);
   return Res;
 }
 
 StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
-  auto *Context = checkCoroutineContext(*this, Loc, "co_return");
-  StmtResult Res = StmtError();
+  return BuildCoreturnStmt(Loc, E);
+}
+StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
+  auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
 
-  if (Context && !Res.isInvalid())
-    Context->CoroutineStmts.push_back(Res.get());
+  // FIXME: Build return_* calls.
+  Stmt *Res = new (Context) CoreturnStmt(Loc, E);
+  if (Coroutine)
+    Coroutine->CoroutineStmts.push_back(Res);
   return Res;
 }
 
@@ -81,26 +265,25 @@ void Sema::CheckCompletedCoroutineBody(F
 
   // 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);
+  if (Fn->FirstReturnLoc.isValid()) {
+    Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
     auto *First = Fn->CoroutineStmts[0];
     Diag(First->getLocStart(), diag::note_declared_coroutine_here)
-      << 0; // FIXME: Indicate the kind here
+      << (isa<CoawaitExpr>(First) ? 0 :
+          isa<CoyieldExpr>(First) ? 1 : 2);
   }
 
   bool AnyCoawaits = false;
   bool AnyCoyields = false;
   for (auto *CoroutineStmt : Fn->CoroutineStmts) {
-    (void)CoroutineStmt;
-    AnyCoawaits = AnyCoyields = true; // FIXME
+    AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt);
+    AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt);
   }
 
   if (!AnyCoawaits && !AnyCoyields)
     Diag(Fn->CoroutineStmts.front()->getLocStart(),
-         diag::ext_coroutine_without_coawait_coyield);
+         diag::ext_coroutine_without_co_await_co_yield);
 
-  // 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.
+  // FIXME: Perform analysis of initial and final suspend,
+  // and set_exception call.
 }

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Oct 27 01:02:45 2015
@@ -1063,8 +1063,10 @@ CanThrowResult Sema::canThrow(const Expr
 
     // Many other things have subexpressions, so we have to test those.
     // Some are simple:
+  case Expr::CoawaitExprClass:
   case Expr::ConditionalOperatorClass:
   case Expr::CompoundLiteralExprClass:
+  case Expr::CoyieldExprClass:
   case Expr::CXXConstCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXStdInitializerListExprClass:

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 27 01:02:45 2015
@@ -10901,6 +10901,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(So
     }
     break;
   case UO_Extension:
+  case UO_Coawait:
     resultType = Input.get()->getType();
     VK = Input.get()->getValueKind();
     OK = Input.get()->getObjectKind();

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 27 01:02:45 2015
@@ -8228,15 +8228,16 @@ void Sema::AddBuiltinOperatorCandidates(
   case OO_Array_New:
   case OO_Array_Delete:
   case OO_Call:
-  case OO_Coawait:
     llvm_unreachable(
                     "Special operators don't use AddBuiltinOperatorCandidates");
 
   case OO_Comma:
   case OO_Arrow:
+  case OO_Coawait:
     // C++ [over.match.oper]p3:
-    //   -- For the operator ',', the unary operator '&', or the
-    //      operator '->', the built-in candidates set is empty.
+    //   -- For the operator ',', the unary operator '&', the
+    //      operator '->', or the operator 'co_await', the
+    //      built-in candidates set is empty.
     break;
 
   case OO_Plus: // '+' is either unary or binary
@@ -12481,13 +12482,14 @@ ExprResult Sema::BuildLiteralOperatorCal
 /// otherwise CallExpr is set to ExprError() and some non-success value
 /// is returned.
 Sema::ForRangeStatus
-Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
-                                SourceLocation RangeLoc, VarDecl *Decl,
-                                BeginEndFunction BEF,
+Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
+                                SourceLocation RangeLoc,
                                 const DeclarationNameInfo &NameInfo,
                                 LookupResult &MemberLookup,
                                 OverloadCandidateSet *CandidateSet,
                                 Expr *Range, ExprResult *CallExpr) {
+  Scope *S = nullptr;
+
   CandidateSet->clear();
   if (!MemberLookup.empty()) {
     ExprResult MemberRef =
@@ -12499,15 +12501,11 @@ Sema::BuildForRangeBeginEndCall(Scope *S
                                  /*TemplateArgs=*/nullptr, S);
     if (MemberRef.isInvalid()) {
       *CallExpr = ExprError();
-      Diag(Range->getLocStart(), diag::note_in_for_range)
-          << RangeLoc << BEF << Range->getType();
       return FRS_DiagnosticIssued;
     }
     *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
     if (CallExpr->isInvalid()) {
       *CallExpr = ExprError();
-      Diag(Range->getLocStart(), diag::note_in_for_range)
-          << RangeLoc << BEF << Range->getType();
       return FRS_DiagnosticIssued;
     }
   } else {
@@ -12538,8 +12536,6 @@ Sema::BuildForRangeBeginEndCall(Scope *S
                                          /*AllowTypoCorrection=*/false);
     if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
       *CallExpr = ExprError();
-      Diag(Range->getLocStart(), diag::note_in_for_range)
-          << RangeLoc << BEF << Range->getType();
       return FRS_DiagnosticIssued;
     }
   }

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Oct 27 01:02:45 2015
@@ -1859,13 +1859,19 @@ static bool FinishForRangeVarDecl(Sema &
 }
 
 namespace {
+// An enum to represent whether something is dealing with a call to begin()
+// or a call to end() in a range-based for loop.
+enum BeginEndFunction {
+  BEF_begin,
+  BEF_end
+};
 
 /// Produce a note indicating which begin/end function was implicitly called
 /// by a C++11 for-range statement. This is often not obvious from the code,
 /// nor from the diagnostics produced when analysing the implicit expressions
 /// required in a for-range statement.
 void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
-                                  Sema::BeginEndFunction BEF) {
+                                  BeginEndFunction BEF) {
   CallExpr *CE = dyn_cast<CallExpr>(E);
   if (!CE)
     return;
@@ -1923,10 +1929,11 @@ static bool ObjCEnumerationCollection(Ex
 ///
 /// 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, SourceLocation CoawaitLoc,
-                           Stmt *First, SourceLocation ColonLoc, Expr *Range,
-                           SourceLocation RParenLoc, BuildForRangeKind Kind) {
+StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
+                                      SourceLocation CoawaitLoc, Stmt *First,
+                                      SourceLocation ColonLoc, Expr *Range,
+                                      SourceLocation RParenLoc,
+                                      BuildForRangeKind Kind) {
   if (!First)
     return StmtError();
 
@@ -1950,7 +1957,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocatio
 
   // Coroutines: 'for co_await' implicitly co_awaits its range.
   if (CoawaitLoc.isValid()) {
-    ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range);
+    ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
     if (Coawait.isInvalid()) return StmtError();
     Range = Coawait.get();
   }
@@ -1990,7 +1997,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocatio
 /// BeginExpr and EndExpr are set and FRS_Success is returned on success;
 /// CandidateSet and BEF are set and some non-success value is returned on
 /// failure.
-static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
+static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
                                             Expr *BeginRange, Expr *EndRange,
                                             QualType RangeType,
                                             VarDecl *BeginVar,
@@ -1999,7 +2006,7 @@ static Sema::ForRangeStatus BuildNonArra
                                             OverloadCandidateSet *CandidateSet,
                                             ExprResult *BeginExpr,
                                             ExprResult *EndExpr,
-                                            Sema::BeginEndFunction *BEF) {
+                                            BeginEndFunction *BEF) {
   DeclarationNameInfo BeginNameInfo(
       &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
   DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
@@ -2020,7 +2027,7 @@ static Sema::ForRangeStatus BuildNonArra
 
     if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
       SourceLocation RangeLoc = BeginVar->getLocation();
-      *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin;
+      *BEF = BeginMemberLookup.empty() ? BEF_end : BEF_begin;
 
       SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch)
           << RangeLoc << BeginRange->getType() << *BEF;
@@ -2034,29 +2041,35 @@ static Sema::ForRangeStatus BuildNonArra
 
   }
 
-  *BEF = Sema::BEF_begin;
+  *BEF = BEF_begin;
   Sema::ForRangeStatus RangeStatus =
-      SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar,
-                                        Sema::BEF_begin, BeginNameInfo,
+      SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, BeginNameInfo,
                                         BeginMemberLookup, CandidateSet,
                                         BeginRange, BeginExpr);
 
-  if (RangeStatus != Sema::FRS_Success)
+  if (RangeStatus != Sema::FRS_Success) {
+    if (RangeStatus == Sema::FRS_DiagnosticIssued)
+      SemaRef.Diag(BeginRange->getLocStart(), diag::note_in_for_range)
+          << ColonLoc << BEF_begin << BeginRange->getType();
     return RangeStatus;
+  }
   if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
                             diag::err_for_range_iter_deduction_failure)) {
     NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
     return Sema::FRS_DiagnosticIssued;
   }
 
-  *BEF = Sema::BEF_end;
+  *BEF = BEF_end;
   RangeStatus =
-      SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar,
-                                        Sema::BEF_end, EndNameInfo,
+      SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, EndNameInfo,
                                         EndMemberLookup, CandidateSet,
                                         EndRange, EndExpr);
-  if (RangeStatus != Sema::FRS_Success)
+  if (RangeStatus != Sema::FRS_Success) {
+    if (RangeStatus == Sema::FRS_DiagnosticIssued)
+      SemaRef.Diag(EndRange->getLocStart(), diag::note_in_for_range)
+          << ColonLoc << BEF_end << EndRange->getType();
     return RangeStatus;
+  }
   if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc,
                             diag::err_for_range_iter_deduction_failure)) {
     NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF);
@@ -2086,10 +2099,9 @@ static StmtResult RebuildForRangeWithDer
     if (AdjustedRange.isInvalid())
       return StmtResult();
 
-    StmtResult SR =
-      SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc,
-                                   AdjustedRange.get(), RParenLoc,
-                                   Sema::BFRK_Check);
+    StmtResult SR = SemaRef.ActOnCXXForRangeStmt(
+        S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(),
+        RParenLoc, Sema::BFRK_Check);
     if (SR.isInvalid())
       return StmtResult();
   }
@@ -2099,8 +2111,8 @@ static StmtResult RebuildForRangeWithDer
   // 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, CoawaitLoc, LoopVarDecl, ColonLoc,
-                                      AdjustedRange.get(), RParenLoc,
+  return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl,
+                                      ColonLoc, AdjustedRange.get(), RParenLoc,
                                       Sema::BFRK_Rebuild);
 }
 
@@ -2127,6 +2139,15 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
                            Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
                            Expr *Inc, Stmt *LoopVarDecl,
                            SourceLocation RParenLoc, BuildForRangeKind Kind) {
+  // FIXME: This should not be used during template instantiation. We should
+  // pick up the set of unqualified lookup results for the != and + operators
+  // in the initial parse.
+  //
+  // Testcase (accepts-invalid):
+  //   template<typename T> void f() { for (auto x : T()) {} }
+  //   namespace N { struct X { X begin(); X end(); int operator*(); }; }
+  //   bool operator!=(N::X, N::X); void operator++(N::X);
+  //   void g() { f<N::X>(); }
   Scope *S = getCurScope();
 
   DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
@@ -2226,9 +2247,9 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
     } else {
       OverloadCandidateSet CandidateSet(RangeLoc,
                                         OverloadCandidateSet::CSK_Normal);
-      Sema::BeginEndFunction BEFFailure;
+      BeginEndFunction BEFFailure;
       ForRangeStatus RangeStatus =
-          BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
+          BuildNonArrayForRange(*this, BeginRangeRef.get(),
                                 EndRangeRef.get(), RangeType,
                                 BeginVar, EndVar, ColonLoc, &CandidateSet,
                                 &BeginExpr, &EndExpr, &BEFFailure);
@@ -2325,7 +2346,7 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
 
     IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
     if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
-      IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get());
+      IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
     if (!IncrExpr.isInvalid())
       IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
     if (IncrExpr.isInvalid()) {
@@ -2364,10 +2385,10 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
   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);
+      IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
+      ColonLoc, RParenLoc);
 }
 
 /// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
@@ -2925,6 +2946,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLoca
   if (CurCap->HasImplicitReturnType || NRVOCandidate)
     FunctionScopes.back()->Returns.push_back(Result);
 
+  if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
+    FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
+
   return Result;
 }
 
@@ -3291,6 +3315,9 @@ StmtResult Sema::BuildReturnStmt(SourceL
   if (Result->getNRVOCandidate())
     FunctionScopes.back()->Returns.push_back(Result);
 
+  if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
+    FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
+
   return Result;
 }
 

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 27 01:02:45 2015
@@ -1287,6 +1287,30 @@ public:
                                     Constraints, Clobbers, Exprs, EndLoc);
   }
 
+  /// \brief Build a new co_return statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result) {
+    return getSema().BuildCoreturnStmt(CoreturnLoc, Result);
+  }
+
+  /// \brief Build a new co_await expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result) {
+    return getSema().BuildCoawaitExpr(CoawaitLoc, Result);
+  }
+
+  /// \brief Build a new co_yield expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildCoyieldExpr(SourceLocation CoyieldLoc, Expr *Result) {
+    return getSema().BuildCoyieldExpr(CoyieldLoc, Result);
+  }
+
   /// \brief Build a new Objective-C \@try statement.
   ///
   /// By default, performs semantic analysis to build the new statement.
@@ -1715,6 +1739,7 @@ public:
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
+                                    SourceLocation CoawaitLoc,
                                     SourceLocation ColonLoc,
                                     Stmt *Range, Stmt *BeginEnd,
                                     Expr *Cond, Expr *Inc,
@@ -1737,7 +1762,6 @@ public:
       }
     }
 
-    SourceLocation CoawaitLoc; // FIXME
     return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
                                           Range, BeginEnd,
                                           Cond, Inc, LoopVar, RParenLoc,
@@ -6403,6 +6427,56 @@ TreeTransform<Derived>::TransformMSAsmSt
                                        TransformedExprs, S->getEndLoc());
 }
 
+// C++ Coroutines TS
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
+  // The coroutine body should be re-formed by the caller if necessary.
+  return getDerived().TransformStmt(S->getBody());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) {
+  ExprResult Result = getDerived().TransformInitializer(S->getOperand(),
+                                                        /*NotCopyInit*/false);
+  if (Result.isInvalid())
+    return StmtError();
+
+  // Always rebuild; we don't know if this needs to be injected into a new
+  // context or if the promise type has changed.
+  return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) {
+  ExprResult Result = getDerived().TransformInitializer(E->getOperand(),
+                                                        /*NotCopyInit*/false);
+  if (Result.isInvalid())
+    return ExprError();
+
+  // Always rebuild; we don't know if this needs to be injected into a new
+  // context or if the promise type has changed.
+  return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCoyieldExpr(CoyieldExpr *E) {
+  ExprResult Result = getDerived().TransformInitializer(E->getOperand(),
+                                                        /*NotCopyInit*/false);
+  if (Result.isInvalid())
+    return ExprError();
+
+  // Always rebuild; we don't know if this needs to be injected into a new
+  // context or if the promise type has changed.
+  return getDerived().RebuildCoyieldExpr(E->getKeywordLoc(), Result.get());
+}
+
+// Objective-C Statements.
+
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
@@ -6692,6 +6766,7 @@ TreeTransform<Derived>::TransformCXXForR
       Inc.get() != S->getInc() ||
       LoopVar.get() != S->getLoopVarStmt()) {
     NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+                                                  S->getCoawaitLoc(),
                                                   S->getColonLoc(), Range.get(),
                                                   BeginEnd.get(), Cond.get(),
                                                   Inc.get(), LoopVar.get(),
@@ -6708,6 +6783,7 @@ TreeTransform<Derived>::TransformCXXForR
   // it now so we have a new statement to attach the body to.
   if (Body.get() != S->getBody() && NewStmt.get() == S) {
     NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+                                                  S->getCoawaitLoc(),
                                                   S->getColonLoc(), Range.get(),
                                                   BeginEnd.get(), Cond.get(),
                                                   Inc.get(), LoopVar.get(),

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct 27 01:02:45 2015
@@ -381,6 +381,26 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsm
                 Constraints, Exprs, Clobbers);
 }
 
+void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
 void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
   VisitStmt(S);
   ++Idx;
@@ -1178,9 +1198,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXT
 
 void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   VisitStmt(S);
-  S->setForLoc(ReadSourceLocation(Record, Idx));
-  S->setColonLoc(ReadSourceLocation(Record, Idx));
-  S->setRParenLoc(ReadSourceLocation(Record, Idx));
+  S->ForLoc = ReadSourceLocation(Record, Idx);
+  S->CoawaitLoc = ReadSourceLocation(Record, Idx);
+  S->ColonLoc = ReadSourceLocation(Record, Idx);
+  S->RParenLoc = ReadSourceLocation(Record, Idx);
   S->setRangeStmt(Reader.ReadSubStmt());
   S->setBeginEndStmt(Reader.ReadSubStmt());
   S->setCond(Reader.ReadSubExpr());

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct 27 01:02:45 2015
@@ -287,6 +287,26 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsm
   Code = serialization::STMT_MSASM;
 }
 
+void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
+void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) {
+  // FIXME: Implement coroutine serialization.
+  llvm_unreachable("unimplemented");
+}
+
 void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
   VisitStmt(S);
   // NumCaptures
@@ -1135,6 +1155,7 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXT
 void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   VisitStmt(S);
   Writer.AddSourceLocation(S->getForLoc(), Record);
+  Writer.AddSourceLocation(S->getCoawaitLoc(), Record);
   Writer.AddSourceLocation(S->getColonLoc(), Record);
   Writer.AddSourceLocation(S->getRParenLoc(), Record);
   Writer.AddStmt(S->getRangeStmt());

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Oct 27 01:02:45 2015
@@ -765,6 +765,10 @@ void ExprEngine::Visit(const Stmt *S, Ex
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
     case Stmt::FunctionParmPackExprClass:
+    case Stmt::CoroutineBodyStmtClass:
+    case Stmt::CoawaitExprClass:
+    case Stmt::CoreturnStmtClass:
+    case Stmt::CoyieldExprClass:
     case Stmt::SEHTryStmtClass:
     case Stmt::SEHExceptStmtClass:
     case Stmt::SEHLeaveStmtClass:

Modified: cfe/trunk/test/Parser/cxx1z-coroutines.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-coroutines.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-coroutines.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-coroutines.cpp Tue Oct 27 01:02:45 2015
@@ -9,7 +9,7 @@ U f(T t) {
   1 + co_yield t; // expected-error {{expected expression}}
 
   auto x = co_await t;
-  auto y = co_yield t;
+  auto y = co_yield t; // expected-error {{void}} FIXME
 
   for co_await (int x : t) {}
   for co_await (int x = 0; x != 10; ++x) {} // expected-error {{'co_await' modifier can only be applied to range-based for loop}}

Modified: cfe/trunk/test/SemaCXX/coroutines.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/coroutines.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/coroutines.cpp (original)
+++ cfe/trunk/test/SemaCXX/coroutines.cpp Tue Oct 27 01:02:45 2015
@@ -1,37 +1,68 @@
 // RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s
 
+struct awaitable {
+  bool await_ready();
+  void await_suspend(); // FIXME: coroutine_handle
+  void await_resume();
+} a;
+
+void no_coroutine_traits() {
+  co_await a; // expected-error {{need to include <coroutine>}}
+}
+
+namespace std {
+  template<typename ...T> struct coroutine_traits; // expected-note {{declared here}}
+};
+
+void no_specialization() {
+  co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}}
+}
+
+template<typename ...T> struct std::coroutine_traits<int, T...> {};
+
+int no_promise_type() {
+  co_await a; // expected-error {{this function cannot be a coroutine: 'coroutine_traits<int>' has no member named 'promise_type'}}
+}
+
+struct promise; // expected-note {{forward declaration}}
+template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };
+
+  // FIXME: This diagnostic is terrible.
+void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
+  co_await a;
+}
+
+struct promise {};
+
 void mixed_yield() {
-  // FIXME: diagnose
-  co_yield 0;
-  return;
+  co_yield 0; // expected-note {{use of 'co_yield'}}
+  return; // expected-error {{not allowed in coroutine}}
 }
 
 void mixed_await() {
-  // FIXME: diagnose
-  co_await 0;
-  return;
+  co_await a; // expected-note {{use of 'co_await'}}
+  return; // expected-error {{not allowed in coroutine}}
 }
 
 void only_coreturn() {
-  // FIXME: diagnose
-  co_return;
+  co_return; // expected-warning {{'co_return' used in a function that uses neither 'co_await' nor 'co_yield'}}
 }
 
 void mixed_coreturn(bool b) {
-  // FIXME: diagnose
   if (b)
-    co_return;
+    // expected-warning at +1 {{'co_return' used in a function that uses neither}}
+    co_return; // expected-note {{use of 'co_return'}}
   else
-    return;
+    return; // expected-error {{not allowed in coroutine}}
 }
 
 struct CtorDtor {
   CtorDtor() {
     co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
   }
-  CtorDtor(int n) {
+  CtorDtor(awaitable a) {
     // The spec doesn't say this is ill-formed, but it must be.
-    co_await n; // expected-error {{'co_await' cannot be used in a constructor}}
+    co_await a; // expected-error {{'co_await' cannot be used in a constructor}}
   }
   ~CtorDtor() {
     co_return 0; // expected-error {{'co_return' cannot be used in a destructor}}
@@ -42,10 +73,35 @@ struct CtorDtor {
   }
 };
 
-constexpr void constexpr_coroutine() {
-  co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
+constexpr void constexpr_coroutine() { // expected-error {{never produces a constant expression}}
+  co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} expected-note {{subexpression}}
 }
 
 void varargs_coroutine(const char *, ...) {
-  co_await 0; // expected-error {{'co_await' cannot be used in a varargs function}}
+  co_await a; // expected-error {{'co_await' cannot be used in a varargs function}}
+}
+
+struct outer {};
+
+namespace dependent_operator_co_await_lookup {
+  template<typename T> void await_template(T t) {
+    // no unqualified lookup results
+    co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}}
+    // expected-error at -1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}}
+  };
+  template void await_template(awaitable);
+
+  struct indirectly_awaitable { indirectly_awaitable(outer); };
+  awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}}
+  template void await_template(indirectly_awaitable);
+
+  struct not_awaitable {};
+  template void await_template(not_awaitable); // expected-note {{instantiation}}
+
+  template<typename T> void await_template_2(T t) {
+    // one unqualified lookup result
+    co_await t;
+  };
+  template void await_template(outer); // expected-note {{instantiation}}
+  template void await_template_2(outer);
 }

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=251387&r1=251386&r2=251387&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Tue Oct 27 01:02:45 2015
@@ -227,6 +227,10 @@ CXCursor cxcursor::MakeCXCursor(const St
   case Stmt::AtomicExprClass:
   case Stmt::BinaryConditionalOperatorClass:
   case Stmt::TypeTraitExprClass:
+  case Stmt::CoroutineBodyStmtClass:
+  case Stmt::CoawaitExprClass:
+  case Stmt::CoreturnStmtClass:
+  case Stmt::CoyieldExprClass:
   case Stmt::CXXBindTemporaryExprClass:
   case Stmt::CXXDefaultArgExprClass:
   case Stmt::CXXDefaultInitExprClass:




More information about the cfe-commits mailing list