[clang] 6d5ea6b - Revert "[Coroutines] Stop supportting std::experimental::coroutine_traits"

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 16 23:51:56 PST 2023


Author: Chuanqi Xu
Date: 2023-02-17T15:50:54+08:00
New Revision: 6d5ea6b123423df136d34f0b99811b5ad3ba1f48

URL: https://github.com/llvm/llvm-project/commit/6d5ea6b123423df136d34f0b99811b5ad3ba1f48
DIFF: https://github.com/llvm/llvm-project/commit/6d5ea6b123423df136d34f0b99811b5ad3ba1f48.diff

LOG: Revert "[Coroutines] Stop supportting std::experimental::coroutine_traits"

This reverts commit c4e6e771f255fb1da3d505534997b6a88195b012.

Since clang-tools-extra contains the use for
std::experimental::coroutine_traits, the previsou commit breaks the
build bot. Revert this one to make the bot green.

Added: 
    clang/test/AST/coroutine-locals-cleanup-exp-namespace.cpp
    clang/test/AST/coroutine-source-location-crash-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-alloc-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-always-inline-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-await-domination-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-await-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-await-resume-eh-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-cleanup-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-dest-slot-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-dwarf-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-eh-cleanup-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-gro-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-gro2-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-lambda-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-newpm-pipeline-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-params-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-promise-dtor-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-ret-void-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-return-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-return-voidtype-initlist-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-symmetric-transfer-01-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-symmetric-transfer-02-exp-namespace.cpp
    clang/test/CodeGenCoroutines/coro-unhandled-exception-exp-namespace.cpp
    clang/test/CodeGenCoroutines/microsoft-abi-operator-coawait-exp-namespace.cpp
    clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp
    clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp
    clang/test/SemaCXX/coreturn-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-mixed3-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp
    clang/test/SemaCXX/coroutine-uninitialized-warning-crash-exp-namespace.cpp
    clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp
    clang/test/SemaCXX/coroutines-exp-namespace.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaCoroutine.cpp
    clang/lib/Sema/SemaDeclCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1ca735baeb278..70a91bab0cb21 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -53,8 +53,6 @@ C/C++ Language Potentially Breaking Changes
 
 C++ Specific Potentially Breaking Changes
 -----------------------------------------
-- Clang won't search for coroutine_traits in std::experimental namespace any more.
-  Clang will only search for std::coroutine_traits for coroutines then.
 
 ABI Changes in This Version
 ---------------------------

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ed6eef1d5e93b..5ab134592e865 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11283,7 +11283,15 @@ def err_coroutine_invalid_func_context : Error<
   "|a consteval function}0">;
 def err_implied_coroutine_type_not_found : Error<
   "%0 type was not found; include <coroutine> before defining "
-  "a coroutine">;
+  "a coroutine; include <experimental/coroutine> if your version "
+  "of libcxx is less than 14.0">;
+def warn_deprecated_coroutine_namespace : Warning<
+  "support for 'std::experimental::%0' will be removed in Clang 17; "
+  "use 'std::%0' instead">,
+  InGroup<DeprecatedExperimentalCoroutine>;
+def err_mixed_use_std_and_experimental_namespace_for_coroutine : Error<
+  "conflicting mixed use of std and std::experimental namespaces for "
+  "coroutine components">;
 def err_implicit_coroutine_std_nothrow_type_not_found : Error<
   "std::nothrow was not found; include <new> before defining a coroutine which "
   "uses get_return_object_on_allocation_failure()">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 08c17a6e1f50b..80b6f9d0ab1d5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1143,6 +1143,10 @@ class Sema final {
   /// standard library.
   LazyDeclPtr StdAlignValT;
 
+  /// The C++ "std::experimental" namespace, where the experimental parts
+  /// of the standard library resides.
+  NamespaceDecl *StdExperimentalNamespaceCache;
+
   /// The C++ "std::initializer_list" template, which is defined in
   /// \<initializer_list>.
   ClassTemplateDecl *StdInitializerList;
@@ -1150,6 +1154,10 @@ class Sema final {
   /// The C++ "std::coroutine_traits" template, which is defined in
   /// \<coroutine_traits>
   ClassTemplateDecl *StdCoroutineTraitsCache;
+  /// The namespace where coroutine components are defined. In standard,
+  /// they are defined in std namespace. And in the previous implementation,
+  /// they are defined in std::experimental namespace.
+  NamespaceDecl *CoroTraitsNamespaceCache;
 
   /// The C++ "type_info" declaration, which is defined in \<typeinfo>.
   RecordDecl *CXXTypeInfoDecl;
@@ -6084,6 +6092,9 @@ class Sema final {
   NamespaceDecl *getStdNamespace() const;
   NamespaceDecl *getOrCreateStdNamespace();
 
+  NamespaceDecl *lookupStdExperimentalNamespace();
+  NamespaceDecl *getCachedCoroNamespace() { return CoroTraitsNamespaceCache; }
+
   CXXRecordDecl *getStdBadAlloc() const;
   EnumDecl *getStdAlignValT() const;
 
@@ -10900,7 +10911,8 @@ class Sema final {
   /// Lookup 'coroutine_traits' in std namespace and std::experimental
   /// namespace. The namespace found is recorded in Namespace.
   ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc,
-                                           SourceLocation FuncLoc);
+                                           SourceLocation FuncLoc,
+                                           NamespaceDecl *&Namespace);
   /// Check that the expression co_await promise.final_suspend() shall not be
   /// potentially-throwing.
   bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend);

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 778d67677bc43..d9d0ed6784f46 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -202,7 +202,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
       IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr),
       LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
-      StdInitializerList(nullptr),
+      StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
       StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr),
       MSVCGuidDecl(nullptr), StdSourceLocationImplDecl(nullptr),
       NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr),

diff  --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 0dcfbd5281d1d..9678e30699c84 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -54,10 +54,12 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
   const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
   const SourceLocation FuncLoc = FD->getLocation();
 
+  NamespaceDecl *CoroNamespace = nullptr;
   ClassTemplateDecl *CoroTraits =
-      S.lookupCoroutineTraits(KwLoc, FuncLoc);
-  if (!CoroTraits)
+      S.lookupCoroutineTraits(KwLoc, FuncLoc, CoroNamespace);
+  if (!CoroTraits) {
     return QualType();
+  }
 
   // Form template argument list for coroutine_traits<R, P1, P2, ...> according
   // to [dcl.fct.def.coroutine]3
@@ -115,7 +117,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
   QualType PromiseType = S.Context.getTypeDeclType(Promise);
 
   auto buildElaboratedType = [&]() {
-    auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, S.getStdNamespace());
+    auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, CoroNamespace);
     NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
                                       CoroTrait.getTypePtr());
     return S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
@@ -140,7 +142,7 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
   if (PromiseType.isNull())
     return QualType();
 
-  NamespaceDecl *CoroNamespace = S.getStdNamespace();
+  NamespaceDecl *CoroNamespace = S.getCachedCoroNamespace();
   assert(CoroNamespace && "Should already be diagnosed");
 
   LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"),
@@ -322,7 +324,7 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
 }
 
 // See if return type is coroutine-handle and if so, invoke builtin coro-resume
-// on its address. This is to enable the support for coroutine-handle
+// on its address. This is to enable experimental support for coroutine-handle
 // returning await_suspend that results in a guaranteed tail call to the target
 // coroutine.
 static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
@@ -430,7 +432,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
     //     type Z.
     QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
 
-    // Support for coroutine_handle returning await_suspend.
+    // Experimental support for coroutine_handle returning await_suspend.
     if (Expr *TailCallSuspend =
             maybeTailCall(S, RetType, AwaitSuspend, Loc))
       // Note that we don't wrap the expression with ExprWithCleanups here
@@ -1840,32 +1842,67 @@ StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
 }
 
 ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
-                                               SourceLocation FuncLoc) {
-  if (StdCoroutineTraitsCache)
-    return StdCoroutineTraitsCache;
+                                               SourceLocation FuncLoc,
+                                               NamespaceDecl *&Namespace) {
+  if (!StdCoroutineTraitsCache) {
+    // Because coroutines moved from std::experimental in the TS to std in
+    // C++20, we look in both places to give users time to transition their
+    // TS-specific code to C++20.  Diagnostics are given when the TS usage is
+    // discovered.
+    // TODO: Become stricter when <experimental/coroutine> is removed.
+
+    IdentifierInfo const &TraitIdent =
+        PP.getIdentifierTable().get("coroutine_traits");
+
+    NamespaceDecl *StdSpace = getStdNamespace();
+    LookupResult ResStd(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
+    bool InStd = StdSpace && LookupQualifiedName(ResStd, StdSpace);
+
+    NamespaceDecl *ExpSpace = lookupStdExperimentalNamespace();
+    LookupResult ResExp(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
+    bool InExp = ExpSpace && LookupQualifiedName(ResExp, ExpSpace);
+
+    if (!InStd && !InExp) {
+      // The goggles, they found nothing!
+      Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
+          << "std::coroutine_traits";
+      return nullptr;
+    }
 
-  IdentifierInfo const &TraitIdent =
-      PP.getIdentifierTable().get("coroutine_traits");
+    // Prefer ::std to std::experimental.
+    LookupResult &Result = InStd ? ResStd : ResExp;
+    CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace;
 
-  NamespaceDecl *StdSpace = getStdNamespace();
-  LookupResult Result(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
-  bool Found = StdSpace && LookupQualifiedName(Result, StdSpace);
+    // coroutine_traits is required to be a class template.
+    StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>();
+    if (!StdCoroutineTraitsCache) {
+      Result.suppressDiagnostics();
+      NamedDecl *Found = *Result.begin();
+      Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
+      return nullptr;
+    }
 
-  if (!Found) {
-    // The goggles, we found nothing!
-    Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
-        << "std::coroutine_traits";
-    return nullptr;
-  }
+    if (InExp) {
+      // Found in std::experimental
+      Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
+          << "coroutine_traits";
+      ResExp.suppressDiagnostics();
+      NamedDecl *Found = *ResExp.begin();
+      Diag(Found->getLocation(), diag::note_entity_declared_at) << Found;
+
+      if (InStd &&
+          StdCoroutineTraitsCache != ResExp.getAsSingle<ClassTemplateDecl>()) {
+        // Also found something 
diff erent in std
+        Diag(KwLoc,
+             diag::err_mixed_use_std_and_experimental_namespace_for_coroutine);
+        Diag(StdCoroutineTraitsCache->getLocation(),
+             diag::note_entity_declared_at)
+            << StdCoroutineTraitsCache;
 
-  // coroutine_traits is required to be a class template.
-  StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>();
-  if (!StdCoroutineTraitsCache) {
-    Result.suppressDiagnostics();
-    NamedDecl *Found = *Result.begin();
-    Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
-    return nullptr;
+        return nullptr;
+      }
+    }
   }
-
+  Namespace = CoroTraitsNamespaceCache;
   return StdCoroutineTraitsCache;
 }

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 7bae979fe061d..df83442a8cd18 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11386,6 +11386,21 @@ NamespaceDecl *Sema::getStdNamespace() const {
   return cast_or_null<NamespaceDecl>(
                                  StdNamespace.get(Context.getExternalSource()));
 }
+
+NamespaceDecl *Sema::lookupStdExperimentalNamespace() {
+  if (!StdExperimentalNamespaceCache) {
+    if (auto Std = getStdNamespace()) {
+      LookupResult Result(*this, &PP.getIdentifierTable().get("experimental"),
+                          SourceLocation(), LookupNamespaceName);
+      if (!LookupQualifiedName(Result, Std) ||
+          !(StdExperimentalNamespaceCache =
+                Result.getAsSingle<NamespaceDecl>()))
+        Result.suppressDiagnostics();
+    }
+  }
+  return StdExperimentalNamespaceCache;
+}
+
 namespace {
 
 enum UnsupportedSTLSelect {

diff  --git a/clang/test/AST/coroutine-locals-cleanup-exp-namespace.cpp b/clang/test/AST/coroutine-locals-cleanup-exp-namespace.cpp
new file mode 100644
index 0000000000000..ca5b28275e7f4
--- /dev/null
+++ b/clang/test/AST/coroutine-locals-cleanup-exp-namespace.cpp
@@ -0,0 +1,109 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -fsyntax-only -ast-dump %s | FileCheck %s
+
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+struct Task {
+  struct promise_type {
+    Task get_return_object() noexcept {
+      return Task{coroutine_handle<promise_type>::from_promise(*this)};
+    }
+
+    void return_void() noexcept {}
+
+    struct final_awaiter {
+      bool await_ready() noexcept { return false; }
+      coroutine_handle<> await_suspend(coroutine_handle<promise_type> h) noexcept {
+        h.destroy();
+        return {};
+      }
+      void await_resume() noexcept {}
+    };
+
+    void unhandled_exception() noexcept {}
+
+    final_awaiter final_suspend() noexcept { return {}; }
+
+    suspend_always initial_suspend() noexcept { return {}; }
+
+    template <typename Awaitable>
+    auto await_transform(Awaitable &&awaitable) {
+      return awaitable.co_viaIfAsync();
+    }
+  };
+
+  using handle_t = coroutine_handle<promise_type>;
+
+  class Awaiter {
+  public:
+    explicit Awaiter(handle_t coro) noexcept;
+    Awaiter(Awaiter &&other) noexcept;
+    Awaiter(const Awaiter &) = delete;
+    ~Awaiter();
+
+    bool await_ready() noexcept { return false; }
+    handle_t await_suspend(coroutine_handle<> continuation) noexcept;
+    void await_resume();
+
+  private:
+    handle_t coro_;
+  };
+
+  Task(handle_t coro) noexcept : coro_(coro) {}
+
+  handle_t coro_;
+
+  Task(const Task &t) = delete;
+  Task(Task &&t) noexcept;
+  ~Task();
+  Task &operator=(Task t) noexcept;
+
+  Awaiter co_viaIfAsync();
+};
+
+static Task foo() {
+  co_return;
+}
+
+Task bar() {
+  auto mode = 2;
+  switch (mode) {
+  case 1:
+    co_await foo();
+    break;
+  case 2:
+    co_await foo();
+    break;
+  default:
+    break;
+  }
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} bar 'Task ()'
+// CHECK:         SwitchStmt
+// CHECK:           CaseStmt
+// CHECK:             ExprWithCleanups {{.*}} 'void'
+// CHECK-NEXT:          CoawaitExpr
+// CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task':'Task' (CXXTemporary {{.*}})
+// CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
+// CHECK:                 ExprWithCleanups {{.*}} 'bool'
+// CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
+// CHECK-NEXT:                MemberExpr {{.*}} .await_ready
+// CHECK:                 CallExpr {{.*}} 'void'
+// CHECK-NEXT:              ImplicitCastExpr {{.*}} 'void (*)(void *)'
+// CHECK-NEXT:                DeclRefExpr {{.*}} '__builtin_coro_resume' 'void (void *)'
+// CHECK-NEXT:              ExprWithCleanups {{.*}} 'void *'
+
+// CHECK:           CaseStmt
+// CHECK:             ExprWithCleanups {{.*}} 'void'
+// CHECK-NEXT:          CoawaitExpr
+// CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task':'Task' (CXXTemporary {{.*}})
+// CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
+// CHECK:                 ExprWithCleanups {{.*}} 'bool'
+// CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
+// CHECK-NEXT:                MemberExpr {{.*}} .await_ready
+// CHECK:                 CallExpr {{.*}} 'void'
+// CHECK-NEXT:              ImplicitCastExpr {{.*}} 'void (*)(void *)'
+// CHECK-NEXT:                DeclRefExpr {{.*}} '__builtin_coro_resume' 'void (void *)'
+// CHECK-NEXT:              ExprWithCleanups {{.*}} 'void *'

diff  --git a/clang/test/AST/coroutine-source-location-crash-exp-namespace.cpp b/clang/test/AST/coroutine-source-location-crash-exp-namespace.cpp
new file mode 100644
index 0000000000000..fb9aaa537c40d
--- /dev/null
+++ b/clang/test/AST/coroutine-source-location-crash-exp-namespace.cpp
@@ -0,0 +1,43 @@
+// Test without serialization:
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN:    -fsyntax-only -ast-dump | FileCheck %s
+//
+// Test with serialization:
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -std=c++14 -fcoroutines-ts -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin9 -std=c++14 -fcoroutines-ts -include-pch %t \
+// RUN: -ast-dump-all /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
+// RUN: | FileCheck %s
+
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+struct A {
+  bool await_ready();
+  void await_resume();
+  template <typename F>
+  void await_suspend(F);
+};
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+// {{0x[0-9a-fA-F]+}} <line:[[@LINE+1]]:1, col:36>
+// CHECK-LABEL: FunctionDecl {{.*}} f 'coro_t (int)'
+coro_t f(int n) {
+  A a{};
+  // CHECK: CoawaitExpr {{0x[0-9a-fA-F]+}} <col:3, col:12>
+  // CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} <col:12>
+  // CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} <col:12>
+  // CHECK-NEXT: CXXMemberCallExpr {{0x[0-9a-fA-F]+}} <col:12>
+  // CHECK-NEXT: MemberExpr {{0x[0-9a-fA-F]+}} <col:12>
+  co_await a;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-alloc-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-alloc-exp-namespace.cpp
new file mode 100644
index 0000000000000..9377fd9e0e8c7
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-alloc-exp-namespace.cpp
@@ -0,0 +1,247 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \
+// RUN:    -Wno-coroutine-missing-unhandled-exception -emit-llvm %s -o - -disable-llvm-passes \
+// RUN:   | FileCheck %s
+
+namespace std {
+namespace experimental {
+template <typename... T>
+struct coroutine_traits; // expected-note {{declared here}}
+
+template <class Promise = void>
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+
+template <>
+struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
+};
+
+} // end namespace experimental
+
+struct nothrow_t {};
+constexpr nothrow_t nothrow = {};
+
+} // end namespace std
+
+// Required when get_return_object_on_allocation_failure() is defined by
+// the promise.
+using SizeT = decltype(sizeof(int));
+void *operator new(SizeT __sz, const std::nothrow_t &) noexcept;
+void operator delete(void *__p, const std::nothrow_t &)noexcept;
+
+struct suspend_always {
+  bool await_ready() noexcept { return false; }
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
+};
+
+struct global_new_delete_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
+  struct promise_type {
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0(global_new_delete_tag) {
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[NeedAlloc:.+]] = call i1 @llvm.coro.alloc(token %[[ID]])
+  // CHECK: br i1 %[[NeedAlloc]], label %[[AllocBB:.+]], label %[[InitBB:.+]]
+
+  // CHECK: [[AllocBB]]:
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: %[[MEM:.+]] = call noalias noundef nonnull ptr @_Znwm(i64 noundef %[[SIZE]])
+  // CHECK: br label %[[InitBB]]
+
+  // CHECK: [[InitBB]]:
+  // CHECK: %[[PHI:.+]] = phi ptr [ null, %{{.+}} ], [ %call, %[[AllocBB]] ]
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(token %[[ID]], ptr %[[PHI]])
+
+  // CHECK: %[[MEM:.+]] = call ptr @llvm.coro.free(token %[[ID]], ptr %[[FRAME]])
+  // CHECK: %[[NeedDealloc:.+]] = icmp ne ptr %[[MEM]], null
+  // CHECK: br i1 %[[NeedDealloc]], label %[[FreeBB:.+]], label %[[Afterwards:.+]]
+
+  // CHECK: [[FreeBB]]:
+  // CHECK: call void @_ZdlPv(ptr noundef %[[MEM]])
+  // CHECK: br label %[[Afterwards]]
+
+  // CHECK: [[Afterwards]]:
+  // CHECK: ret void
+  co_return;
+}
+
+struct promise_new_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<void, promise_new_tag> {
+  struct promise_type {
+    void *operator new(unsigned long);
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(promise_new_tag) {
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: call noundef ptr @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 noundef %[[SIZE]])
+
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+  // CHECK: %[[MEM:.+]] = call ptr @llvm.coro.free(token %[[ID]], ptr %[[FRAME]])
+  // CHECK: call void @_ZdlPv(ptr noundef %[[MEM]])
+  co_return;
+}
+
+struct promise_matching_placement_new_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<void, promise_matching_placement_new_tag, int, float, double> {
+  struct promise_type {
+    void *operator new(unsigned long, promise_matching_placement_new_tag,
+                       int, float, double);
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// CHECK-LABEL: f1a(
+extern "C" void f1a(promise_matching_placement_new_tag, int x, float y, double z) {
+  // CHECK: store i32 %x, ptr %x.addr, align 4
+  // CHECK: store float %y, ptr %y.addr, align 4
+  // CHECK: store double %z, ptr %z.addr, align 8
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: %[[INT:.+]] = load i32, ptr %x.addr, align 4
+  // CHECK: %[[FLOAT:.+]] = load float, ptr %y.addr, align 4
+  // CHECK: %[[DOUBLE:.+]] = load double, ptr %z.addr, align 8
+  // CHECK: call noundef ptr @_ZNSt12experimental16coroutine_traitsIJv34promise_matching_placement_new_tagifdEE12promise_typenwEmS1_ifd(i64 noundef %[[SIZE]], i32 noundef %[[INT]], float noundef %[[FLOAT]], double noundef %[[DOUBLE]])
+  co_return;
+}
+
+// Declare a placement form operator new, such as the one described in
+// C++ 18.6.1.3.1, which takes a ptr argument.
+void *operator new(SizeT __sz, void *__p) noexcept;
+
+struct promise_matching_global_placement_new_tag {};
+struct dummy {};
+template <>
+struct std::experimental::coroutine_traits<void, promise_matching_global_placement_new_tag, dummy *> {
+  struct promise_type {
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// A coroutine that takes a single pointer argument should not invoke this
+// placement form operator. [dcl.fct.def.coroutine]/7 dictates that lookup for
+// allocation functions matching the coroutine function's signature be done
+// within the scope of the promise type's class.
+// CHECK-LABEL: f1b(
+extern "C" void f1b(promise_matching_global_placement_new_tag, dummy *) {
+  // CHECK: call noalias noundef nonnull ptr @_Znwm(i64
+  co_return;
+}
+
+struct promise_delete_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<void, promise_delete_tag> {
+  struct promise_type {
+    void operator delete(void *);
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// CHECK-LABEL: f2(
+extern "C" void f2(promise_delete_tag) {
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef %[[SIZE]])
+
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+  // CHECK: %[[MEM:.+]] = call ptr @llvm.coro.free(token %[[ID]], ptr %[[FRAME]])
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(ptr noundef %[[MEM]])
+  co_return;
+}
+
+struct promise_sized_delete_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<void, promise_sized_delete_tag> {
+  struct promise_type {
+    void operator delete(void *, unsigned long);
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+  };
+};
+
+// CHECK-LABEL: f3(
+extern "C" void f3(promise_sized_delete_tag) {
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef %[[SIZE]])
+
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+  // CHECK: %[[MEM:.+]] = call ptr @llvm.coro.free(token %[[ID]], ptr %[[FRAME]])
+  // CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(ptr noundef %[[MEM]], i64 noundef %[[SIZE2]])
+  co_return;
+}
+
+struct promise_on_alloc_failure_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
+  struct promise_type {
+    int get_return_object() { return 0; }
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    static int get_return_object_on_allocation_failure() { return -1; }
+  };
+};
+
+// CHECK-LABEL: f4(
+extern "C" int f4(promise_on_alloc_failure_tag) {
+  // CHECK: %[[RetVal:.+]] = alloca i32
+  // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+  // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: %[[MEM:.+]] = call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], ptr noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow)
+  // CHECK: %[[OK:.+]] = icmp ne ptr %[[MEM]], null
+  // CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]]
+
+  // CHECK: [[ERRBB]]:
+  // CHECK:   %[[FailRet:.+]] = call noundef i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
+  // CHECK:   store i32 %[[FailRet]], ptr %[[RetVal]]
+  // CHECK:   br label %[[RetBB:.+]]
+
+  // CHECK: [[OKBB]]:
+  // CHECK:   %[[OkRet:.+]] = call noundef i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv(
+
+  // CHECK: [[RetBB]]:
+  // CHECK:   %[[LoadRet:.+]] = load i32, ptr %[[RetVal]], align 4
+  // CHECK:   ret i32 %[[LoadRet]]
+  co_return;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-always-inline-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-always-inline-exp-namespace.cpp
new file mode 100644
index 0000000000000..2db4764a934ec
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-always-inline-exp-namespace.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
+// RUN:   -O0 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
+// RUN:   -fno-inline -O0 %s -o - | FileCheck %s
+
+namespace std {
+namespace experimental {
+
+struct handle {};
+
+struct awaitable {
+  bool await_ready() noexcept { return true; }
+  // CHECK-NOT: await_suspend
+  inline void __attribute__((__always_inline__)) await_suspend(handle) noexcept {}
+  bool await_resume() noexcept { return true; }
+};
+
+template <typename T>
+struct coroutine_handle {
+  static handle from_address(void *address) noexcept { return {}; }
+};
+
+template <typename T = void>
+struct coroutine_traits {
+  struct promise_type {
+    awaitable initial_suspend() { return {}; }
+    awaitable final_suspend() noexcept { return {}; }
+    void return_void() {}
+    T get_return_object() { return T(); }
+    void unhandled_exception() {}
+  };
+};
+} // namespace experimental
+} // namespace std
+
+// CHECK-LABEL: @_Z3foov
+// CHECK-LABEL: entry:
+// CHECK: call void @llvm.lifetime.start.p0(i64 1, ptr %ref.tmp{{.*}})
+// CHECK: call void @llvm.lifetime.end.p0(i64 1, ptr %ref.tmp{{.*}})
+
+// CHECK: call void @llvm.lifetime.start.p0(i64 1, ptr %ref.tmp{{.*}})
+// CHECK: call void @llvm.lifetime.end.p0(i64 1, ptr %ref.tmp{{.*}})
+void foo() { co_return; }

diff  --git a/clang/test/CodeGenCoroutines/coro-await-domination-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-await-domination-exp-namespace.cpp
new file mode 100644
index 0000000000000..008867eb4bcf1
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-await-domination-exp-namespace.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - | FileCheck %s
+#include "Inputs/coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+struct coro {
+  struct promise_type {
+    coro get_return_object();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+struct A {
+  ~A();
+  bool await_ready();
+  int await_resume() { return 8; }
+  template <typename F> void await_suspend(F);
+};
+
+extern "C" void consume(int);
+
+// Verifies that domination is properly built during cleanup.
+// Without CGCleanup.cpp fix verifier was reporting:
+// Instruction does not dominate all uses!
+//  %tmp.exprcleanup = alloca i32*, align 8
+//  store i32* %x, i32** %tmp.exprcleanup, align 8
+
+// CHECK-LABEL: f(
+extern "C" coro f(int) {
+  int x = 42;
+  x = co_await A{};
+  consume(x);
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-await-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-await-exp-namespace.cpp
new file mode 100644
index 0000000000000..6efbaa3e01739
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-await-exp-namespace.cpp
@@ -0,0 +1,355 @@
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \
+// RUN:   -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s
+
+namespace std {
+namespace experimental {
+template <typename... T>
+struct coroutine_traits;
+
+template <typename Promise = void> struct coroutine_handle;
+
+template <>
+struct coroutine_handle<void> {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+  void *address();
+};
+
+template <typename Promise>
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *) noexcept;
+};
+
+} // namespace experimental
+} // namespace std
+
+struct init_susp {
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+struct final_susp {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template <>
+struct std::experimental::coroutine_traits<void> {
+  struct promise_type {
+    void get_return_object();
+    init_susp initial_suspend();
+    final_susp final_suspend() noexcept;
+    void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+
+  // See if initial_suspend was issued:
+  // ----------------------------------
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
+  // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(ptr
+  // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
+  // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --------------------------
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(ptr {{[^,]*}} %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // ---------------------
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---------------------------
+  // Build the coroutine handle and pass it to await_suspend
+  // ---------------------------
+  // CHECK: call ptr @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(ptr %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an ptr scalar
+  // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])
+  // -------------------------
+  // Generate a suspend point:
+  // -------------------------
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // -----------------------
+  // CHECK: [[CLEANUP_BB]]:
+
+  // When coroutine is resumed, call await_resume
+  // --------------------------
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(ptr {{[^,]*}} %[[AWAITABLE]])
+
+  // See if final_suspend was issued:
+  // ----------------------------------
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
+  // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(ptr
+  // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
+  // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template <>
+struct std::experimental::coroutine_traits<void, int> {
+  struct promise_type {
+    void get_return_object();
+    init_susp initial_suspend();
+    final_susp final_suspend() noexcept;
+    void return_void();
+    suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits<void, int>::promise_type"
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+  co_yield 42;
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(ptr sret(%struct.suspend_maybe) align 4 %[[AWAITER:.+]], ptr {{[^,]*}} %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --------------------------
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(ptr {{[^,]*}} %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // ---------------------
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---------------------------
+  // Build the coroutine handle and pass it to await_suspend
+  // ---------------------------
+  // CHECK: call ptr @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(ptr %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an ptr scalar
+  // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}
+  // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12experimental16coroutine_handleIvEE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])
+  // -------------------------------------------
+  // See if await_suspend decided not to suspend
+  // -------------------------------------------
+  // CHECK: br i1 %[[YES]], label %[[SUSPEND_PLEASE:.+]], label %[[READY_BB]]
+
+  // CHECK: [[SUSPEND_PLEASE]]:
+  // CHECK:    call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+
+  // CHECK: [[READY_BB]]:
+  // CHECK:     call void @_ZN13suspend_maybe12await_resumeEv(ptr {{[^,]*}} %[[AWAITABLE]])
+}
+
+struct ComplexAwaiter {
+  template <typename F> void await_suspend(F);
+  bool await_ready();
+  _Complex float await_resume();
+};
+extern "C" void UseComplex(_Complex float);
+
+// CHECK-LABEL: @TestComplex(
+extern "C" void TestComplex() {
+  UseComplex(co_await ComplexAwaiter{});
+  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
+  // CHECK: call void @UseComplex(<2 x float> %{{.+}})
+
+  co_await ComplexAwaiter{};
+  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
+
+  _Complex float Val = co_await ComplexAwaiter{};
+  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
+}
+
+struct Aggr {
+  int X, Y, Z;
+  ~Aggr();
+};
+struct AggrAwaiter {
+  template <typename F> void await_suspend(F);
+  bool await_ready();
+  Aggr await_resume();
+};
+
+extern "C" void Whatever();
+extern "C" void UseAggr(Aggr &&);
+
+// FIXME: Once the cleanup code is in, add testing that destructors for Aggr
+// are invoked properly on the cleanup branches.
+
+// CHECK-LABEL: @TestAggr(
+extern "C" void TestAggr() {
+  UseAggr(co_await AggrAwaiter{});
+  Whatever();
+  // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr sret(%struct.Aggr) align 4 %[[AwaitResume:.+]],
+  // CHECK: call void @UseAggr(ptr nonnull align 4 dereferenceable(12) %[[AwaitResume]])
+  // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume]])
+  // CHECK: call void @Whatever()
+
+  co_await AggrAwaiter{};
+  Whatever();
+  // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr sret(%struct.Aggr) align 4 %[[AwaitResume2:.+]],
+  // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume2]])
+  // CHECK: call void @Whatever()
+
+  Aggr Val = co_await AggrAwaiter{};
+  Whatever();
+  // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr sret(%struct.Aggr) align 4 %[[AwaitResume3:.+]],
+  // CHECK: call void @Whatever()
+  // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume3]])
+}
+
+struct ScalarAwaiter {
+  template <typename F> void await_suspend(F);
+  bool await_ready();
+  int await_resume();
+};
+
+extern "C" void UseScalar(int);
+
+// CHECK-LABEL: @TestScalar(
+extern "C" void TestScalar() {
+  UseScalar(co_await ScalarAwaiter{});
+  // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
+  // CHECK: call void @UseScalar(i32 %[[Result]])
+
+  int Val = co_await ScalarAwaiter{};
+  // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
+  // CHECK: store i32 %[[Result2]], ptr %[[TMP_EXPRCLEANUP:.+]],
+  // CHECK: %[[TMP:.+]] = load i32, ptr %[[TMP_EXPRCLEANUP]],
+  // CHECK: store i32 %[[TMP]], ptr %Val,
+
+  co_await ScalarAwaiter{};
+  // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
+}
+
+// Test operator co_await codegen.
+enum class MyInt : int {};
+ScalarAwaiter operator co_await(MyInt);
+
+struct MyAgg {
+  AggrAwaiter operator co_await();
+};
+
+// CHECK-LABEL: @TestOpAwait(
+extern "C" void TestOpAwait() {
+  co_await MyInt(42);
+  // CHECK: call void @_Zaw5MyInt(i32 42)
+  // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr {{[^,]*}} %
+
+  co_await MyAgg{};
+  // CHECK: call void @_ZN5MyAggawEv(ptr {{[^,]*}} %
+  // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr sret(%struct.Aggr) align 4 %
+}
+
+// CHECK-LABEL: EndlessLoop(
+extern "C" void EndlessLoop() {
+  // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
+
+  // See if initial_suspend was issued:
+  // ----------------------------------
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
+  // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(ptr
+
+  for (;;)
+    co_await suspend_always{};
+
+  // Verify that final_suspend was NOT issued:
+  // ----------------------------------
+  // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
+  // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(ptr
+}
+
+// Verifies that we don't crash when awaiting on an lvalue.
+// CHECK-LABEL: @_Z11AwaitLValuev(
+void AwaitLValue() {
+  suspend_always lval;
+  co_await lval;
+}
+
+struct RefTag {};
+
+struct AwaitResumeReturnsLValue {
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  RefTag &await_resume();
+};
+
+template <>
+struct std::experimental::coroutine_traits<void, double> {
+  struct promise_type {
+    void get_return_object();
+    init_susp initial_suspend();
+    final_susp final_suspend() noexcept;
+    void return_void();
+    AwaitResumeReturnsLValue yield_value(int);
+  };
+};
+
+// Verifies that we don't crash when returning an lvalue from an await_resume()
+// expression.
+// CHECK-LABEL:  define{{.*}} void @_Z18AwaitReturnsLValued(double %0)
+void AwaitReturnsLValue(double) {
+  AwaitResumeReturnsLValue a;
+  // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+  // CHECK: %[[XVAR:.+]] = alloca ptr,
+
+  // CHECK: %[[YVAR:.+]] = alloca ptr,
+  // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+
+  // CHECK: %[[TMP_EXPRCLEANUP1:.+]] = alloca ptr,
+  // CHECK: %[[ZVAR:.+]] = alloca ptr,
+  // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+  // CHECK: %[[TMP_EXPRCLEANUP2:.+]] = alloca ptr,
+
+  // CHECK: %[[RES1:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[AVAR]])
+  // CHECK-NEXT: store ptr %[[RES1]], ptr %[[XVAR]],
+  RefTag &x = co_await a;
+
+  // CHECK: %[[RES2:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[TMP1]])
+  // CHECK-NEXT: store ptr %[[RES2]], ptr %[[TMP_EXPRCLEANUP1]],
+  // CHECK: %[[LOAD_TMP1:.+]] = load ptr, ptr %[[TMP_EXPRCLEANUP1]],
+  // CHECK: store ptr %[[LOAD_TMP1]], ptr %[[YVAR]],
+
+  RefTag &y = co_await AwaitResumeReturnsLValue{};
+  // CHECK: %[[RES3:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[TMP2]])
+  // CHECK-NEXT: store ptr %[[RES3]], ptr %[[TMP_EXPRCLEANUP2]],
+  // CHECK: %[[LOAD_TMP2:.+]] = load ptr, ptr %[[TMP_EXPRCLEANUP2]],
+  // CHECK: store ptr %[[LOAD_TMP2]], ptr %[[ZVAR]],
+  RefTag &z = co_yield 42;
+}
+
+struct TailCallAwait {
+  bool await_ready();
+  std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+// CHECK-LABEL: @TestTailcall(
+extern "C" void TestTailcall() {
+  co_await TailCallAwait{};
+
+  // CHECK: %[[RESULT:.+]] = call ptr @_ZN13TailCallAwait13await_suspendENSt12experimental16coroutine_handleIvEE(ptr
+  // CHECK: %[[COERCE:.+]] = getelementptr inbounds %"struct.std::experimental::coroutine_handle", ptr %[[TMP:.+]], i32 0, i32 0
+  // CHECK: store ptr %[[RESULT]], ptr %[[COERCE]]
+  // CHECK: %[[ADDR:.+]] = call ptr @_ZNSt12experimental16coroutine_handleIvE7addressEv(ptr {{[^,]*}} %[[TMP]])
+  // CHECK: call void @llvm.coro.resume(ptr %[[ADDR]])
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-await-resume-eh-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-await-resume-eh-exp-namespace.cpp
new file mode 100644
index 0000000000000..380ce751e6c81
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-await-resume-eh-exp-namespace.cpp
@@ -0,0 +1,114 @@
+// Test the behavior of http://wg21.link/P0664, a proposal to catch any
+// exceptions thrown after the initial suspend point of a coroutine by
+// executing the handler specified by the promise type's 'unhandled_exception'
+// member function.
+//
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts \
+// RUN:   -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   -fexceptions -fcxx-exceptions -disable-llvm-passes \
+// RUN:   | FileCheck %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct throwing_awaitable {
+  bool await_ready() { return true; }
+  void await_suspend(coro::coroutine_handle<>) {}
+  void await_resume() { throw 42; }
+};
+
+struct throwing_task {
+  struct promise_type {
+    auto get_return_object() { return throwing_task{}; }
+    auto initial_suspend() { return throwing_awaitable{}; }
+    auto final_suspend() noexcept { return coro::suspend_never{}; }
+    void return_void() {}
+    void unhandled_exception() {}
+  };
+};
+
+// CHECK-LABEL: define{{.*}} void @_Z1fv()
+throwing_task f() {
+  // A variable RESUMETHREW is used to keep track of whether the body
+  // of 'await_resume' threw an exception. Exceptions thrown in
+  // 'await_resume' are unwound to RESUMELPAD.
+  // CHECK: init.ready:
+  // CHECK-NEXT: store i1 true, ptr %[[RESUMETHREW:.+]], align 1
+  // CHECK-NEXT: invoke void @_ZN18throwing_awaitable12await_resumeEv
+  // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]]
+
+  // If 'await_resume' does not throw an exception, 'false' is stored in
+  // variable RESUMETHREW.
+  // CHECK: [[RESUMECONT]]:
+  // CHECK-NEXT: store i1 false, ptr %[[RESUMETHREW]]
+  // CHECK-NEXT: br label %[[RESUMETRYCONT:.+]]
+
+  // 'unhandled_exception' is called for the exception thrown in
+  // 'await_resume'. The variable RESUMETHREW is never set to false,
+  // and a jump is made to RESUMETRYCONT.
+  // CHECK: [[RESUMELPAD]]:
+  // CHECK: br label %[[RESUMECATCH:.+]]
+  // CHECK: [[RESUMECATCH]]:
+  // CHECK: invoke void @_ZN13throwing_task12promise_type19unhandled_exceptionEv
+  // CHECK-NEXT: to label %[[RESUMEENDCATCH:.+]] unwind label
+  // CHECK: [[RESUMEENDCATCH]]:
+  // CHECK-NEXT: invoke void @__cxa_end_catch()
+  // CHECK-NEXT: to label %[[RESUMEENDCATCHCONT:.+]] unwind label
+  // CHECK: [[RESUMEENDCATCHCONT]]:
+  // CHECK-NEXT: br label %[[RESUMETRYCONT]]
+  // CHECK: [[RESUMETRYCONT]]:
+  // CHECK-NEXT: br label %[[CLEANUP:.+]]
+  // CHECK: [[CLEANUP]]:
+  // CHECK: switch i32 %{{.+}}, label %{{.+}} [
+  // CHECK-NEXT: i32 0, label %[[CLEANUPCONT:.+]]
+  // CHECK-NEXT: ]
+
+  // The variable RESUMETHREW is loaded and if true, then 'await_resume'
+  // threw an exception and the coroutine body is skipped, and the final
+  // suspend is executed immediately. Otherwise, the coroutine body is
+  // executed, and then the final suspend.
+  // CHECK: [[CLEANUPCONT]]:
+  // CHECK-NEXT: %[[RESUMETHREWLOAD:.+]] = load i1, ptr %[[RESUMETHREW]]
+  // CHECK-NEXT: br i1 %[[RESUMETHREWLOAD]], label %[[RESUMEDCONT:.+]], label %[[RESUMEDBODY:.+]]
+
+  // CHECK: [[RESUMEDBODY]]:
+  // CHECK: invoke void @_ZN13throwing_task12promise_type11return_voidEv
+  // CHECK-NEXT: to label %[[REDUMEDBODYCONT:.+]] unwind label
+  // CHECK: [[REDUMEDBODYCONT]]:
+  // CHECK-NEXT: br label %[[COROFINAL:.+]]
+
+  // CHECK: [[RESUMEDCONT]]:
+  // CHECK-NEXT: br label %[[COROFINAL]]
+
+  // CHECK: [[COROFINAL]]:
+  // CHECK: call void @_ZN13throwing_task12promise_type13final_suspendEv
+  co_return;
+}
+
+struct noexcept_awaitable {
+  bool await_ready() { return true; }
+  void await_suspend(coro::coroutine_handle<>) {}
+  void await_resume() noexcept {}
+};
+
+struct noexcept_task {
+  struct promise_type {
+    auto get_return_object() { return noexcept_task{}; }
+    auto initial_suspend() { return noexcept_awaitable{}; }
+    auto final_suspend() noexcept { return coro::suspend_never{}; }
+    void return_void() {}
+    void unhandled_exception() {}
+  };
+};
+
+// CHECK-LABEL: define{{.*}} void @_Z1gv()
+noexcept_task g() {
+  // If the await_resume function is marked as noexcept, none of the additional
+  // conditions that are present in f() above are added to the IR.
+  // This means that no i1 are stored before or after calling await_resume:
+  // CHECK: init.ready:
+  // CHECK-NEXT: call void @_ZN18noexcept_awaitable12await_resumeEv
+  // CHECK-NOT: store i1 false, ptr
+  co_return;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-cleanup-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-cleanup-exp-namespace.cpp
new file mode 100644
index 0000000000000..03023cc0694d2
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-cleanup-exp-namespace.cpp
@@ -0,0 +1,99 @@
+// Verify that coroutine promise and allocated memory are freed up on exception.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+  struct promise_type {
+    void get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    promise_type();
+    ~promise_type();
+    void unhandled_exception() noexcept;
+  };
+};
+
+struct Cleanup {
+  ~Cleanup();
+};
+void may_throw();
+
+// CHECK-LABEL: define{{.*}} void @_Z1fv(
+void f() {
+  // CHECK: call noalias noundef nonnull ptr @_Znwm(i64
+
+  // If promise constructor throws, check that we free the memory.
+
+  // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev(
+  // CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]]
+
+  // CHECK: [[DeallocPad]]:
+  // CHECK-NEXT: landingpad
+  // CHECK-NEXT:   cleanup
+  // CHECK: br label %[[Dealloc:.+]]
+
+  Cleanup cleanup;
+  may_throw();
+
+  // if may_throw throws, check that we destroy the promise and free the memory.
+
+  // CHECK: invoke void @_Z9may_throwv(
+  // CHECK-NEXT: to label %{{.+}} unwind label %[[CatchPad:.+]]
+
+  // CHECK: [[CatchPad]]:
+  // CHECK-NEXT:  landingpad
+  // CHECK-NEXT:       catch ptr null
+  // CHECK:  call void @_ZN7CleanupD1Ev(
+  // CHECK:  br label %[[Catch:.+]]
+
+  // CHECK: [[Catch]]:
+  // CHECK:    call ptr @__cxa_begin_catch(
+  // CHECK:    call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv(
+  // CHECK:    invoke void @__cxa_end_catch()
+  // CHECK-NEXT:    to label %[[Cont:.+]] unwind
+
+  // CHECK: [[Cont]]:
+  // CHECK-NEXT: br label %[[Cont2:.+]]
+  // CHECK: [[Cont2]]:
+  // CHECK-NEXT: br label %[[Cleanup:.+]]
+
+  // CHECK: [[Cleanup]]:
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeD1Ev(
+  // CHECK: %[[Mem0:.+]] = call ptr @llvm.coro.free(
+  // CHECK: call void @_ZdlPv(ptr noundef %[[Mem0]]
+
+  // CHECK: [[Dealloc]]:
+  // CHECK:   %[[Mem:.+]] = call ptr @llvm.coro.free(
+  // CHECK:   call void @_ZdlPv(ptr noundef %[[Mem]])
+
+  co_return;
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z1gv(
+void g() {
+  for (;;)
+    co_await suspend_always{};
+  // Since this is the endless loop there should be no fallthrough handler (call to 'return_void').
+  // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-dest-slot-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-dest-slot-exp-namespace.cpp
new file mode 100644
index 0000000000000..14be9a1d03601
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-dest-slot-exp-namespace.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+struct coro {
+  struct promise_type {
+    coro get_return_object();
+    suspend_always initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+extern "C" coro f(int) { co_return; }
+// Verify that cleanup.dest.slot is eliminated in a coroutine.
+// CHECK-LABEL: f(
+// CHECK: %[[INIT_SUSPEND:.+]] = call i8 @llvm.coro.suspend(
+// CHECK-NEXT: switch i8 %[[INIT_SUSPEND]], label
+// CHECK-NEXT:   i8 0, label %[[INIT_READY:.+]]
+// CHECK-NEXT:   i8 1, label %[[INIT_CLEANUP:.+]]
+// CHECK-NEXT: ]
+// CHECK: %[[CLEANUP_DEST0:.+]] = phi i32 [ 0, %[[INIT_READY]] ], [ 2, %[[INIT_CLEANUP]] ]
+
+// CHECK: %[[FINAL_SUSPEND:.+]] = call i8 @llvm.coro.suspend(
+// CHECK-NEXT: switch i8 %{{.*}}, label %coro.ret [
+// CHECK-NEXT:   i8 0, label %[[FINAL_READY:.+]]
+// CHECK-NEXT:   i8 1, label %[[FINAL_CLEANUP:.+]]
+// CHECK-NEXT: ]
+
+// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(
+// CHECK: %[[CLEANUP_DEST1:.+]] = phi i32 [ 0, %[[FINAL_READY]] ], [ 2, %[[FINAL_CLEANUP]] ]
+// CHECK: %[[CLEANUP_DEST2:.+]] = phi i32 [ %[[CLEANUP_DEST0]], %{{.+}} ], [ %[[CLEANUP_DEST1]], %{{.+}} ], [ 0, %{{.+}} ]
+// CHECK: call ptr @llvm.coro.free(
+// CHECK: switch i32 %[[CLEANUP_DEST2]], label %{{.+}} [
+// CHECK-NEXT: i32 0
+// CHECK-NEXT: i32 2
+// CHECK-NEXT: ]

diff  --git a/clang/test/CodeGenCoroutines/coro-dwarf-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-dwarf-exp-namespace.cpp
new file mode 100644
index 0000000000000..2849f8d80f795
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-dwarf-exp-namespace.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -disable-llvm-optzns -std=c++2a -fcoroutines-ts \
+// RUN:            -triple=x86_64 -dwarf-version=4 -debug-info-kind=limited \
+// RUN:            -emit-llvm -o - %s | \
+// RUN:            FileCheck %s --implicit-check-not=DILocalVariable
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
+  struct promise_type {
+    void get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    promise_type();
+    ~promise_type() noexcept;
+    void unhandled_exception() noexcept;
+  };
+};
+
+// TODO: Not supported yet
+struct CopyOnly {
+  int val;
+  CopyOnly(const CopyOnly &) noexcept;
+  CopyOnly(CopyOnly &&) = delete;
+  ~CopyOnly();
+};
+
+struct MoveOnly {
+  int val;
+  MoveOnly(const MoveOnly &) = delete;
+  MoveOnly(MoveOnly &&) noexcept;
+  ~MoveOnly();
+};
+
+struct MoveAndCopy {
+  int val;
+  MoveAndCopy(const MoveAndCopy &) noexcept;
+  MoveAndCopy(MoveAndCopy &&) noexcept;
+  ~MoveAndCopy();
+};
+
+void consume(int, int, int) noexcept;
+
+void f_coro(int val, MoveOnly moParam, MoveAndCopy mcParam) {
+  consume(val, moParam.val, mcParam.val);
+  co_return;
+}
+
+// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "f_coro", linkageName: "_Z6f_coroi8MoveOnly11MoveAndCopy"
+// CHECK: !{{[0-9]+}} = !DILocalVariable(name: "val", arg: 1, scope: ![[SP]], file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+// CHECK: !{{[0-9]+}} = !DILocalVariable(name: "moParam", arg: 2, scope: ![[SP]], file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+// CHECK: !{{[0-9]+}} = !DILocalVariable(name: "mcParam", arg: 3, scope: ![[SP]], file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
+// CHECK: !{{[0-9]+}} = !DILocalVariable(name: "__promise",

diff  --git a/clang/test/CodeGenCoroutines/coro-eh-cleanup-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-eh-cleanup-exp-namespace.cpp
new file mode 100644
index 0000000000000..9ba91e77004fa
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-eh-cleanup-exp-namespace.cpp
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s
+
+namespace std::experimental {
+template <typename R, typename... T> struct coroutine_traits {
+  using promise_type = typename R::promise_type;
+};
+
+template <class Promise = void> struct coroutine_handle;
+
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+template <class Promise> struct coroutine_handle : coroutine_handle<void> {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    void unhandled_exception() noexcept;
+  };
+};
+
+struct Cleanup {
+  ~Cleanup();
+};
+void may_throw();
+
+coro_t f() {
+  Cleanup x;
+  may_throw();
+  co_return;
+}
+
+// CHECK: @"?f@@YA?AUcoro_t@@XZ"(
+// CHECK:   invoke void @"?may_throw@@YAXXZ"()
+// CHECK:       to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]]
+// CHECK: [[EHCLEANUP]]:
+// CHECK:   %[[INNERPAD:.+]] = cleanuppad within none []
+// CHECK:   call void @"??1Cleanup@@QEAA at XZ"(
+// CHECK:   cleanupret from %{{.+}} unwind label %[[CATCHDISPATCH:.+]]
+
+// CHECK: [[CATCHDISPATCH]]:
+// CHECK:   catchswitch within none [label %[[CATCHPAD:.+]]] unwind label %[[COROENDBB:.+]]
+// CHECK: [[CATCHPAD]]:
+// CHECK:   call void @"?unhandled_exception at promise_type@coro_t@@QEAAXXZ"
+
+// CHECK: [[COROENDBB]]:
+// CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none
+// CHECK-NEXT: call i1 @llvm.coro.end(ptr null, i1 true) [ "funclet"(token %[[CLPAD]]) ]
+// CHECK-NEXT: cleanupret from %[[CLPAD]] unwind label
+
+// CHECK-LPAD: @_Z1fv(
+// CHECK-LPAD:   invoke void @_Z9may_throwv()
+// CHECK-LPAD:       to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]]
+// CHECK-LPAD: [[EHCLEANUP]]:
+// CHECK-LPAD:    landingpad { ptr, i32 }
+// CHECK-LPAD:          catch
+// CHECK-LPAD:   call void @_ZN7CleanupD1Ev(
+// CHECK-LPAD:   call ptr @__cxa_begin_catch
+// CHECK-LPAD:   call void @_ZN6coro_t12promise_type19unhandled_exceptionEv
+// CHECK-LPAD:   invoke void @__cxa_end_catch()
+// CHECK-LPAD:             to label %{{.+}} unwind label %[[UNWINDBB:.+]]
+
+// CHECK-LPAD: [[UNWINDBB]]:
+// CHECK-LPAD:   %[[I1RESUME:.+]] = call i1 @llvm.coro.end(ptr null, i1 true)
+// CHECK-LPAD:   br i1  %[[I1RESUME]], label %[[EHRESUME:.+]], label
+// CHECK-LPAD: [[EHRESUME]]:
+// CHECK-LPAD-NEXT:  %[[exn:.+]] = load ptr, ptr %exn.slot, align 8
+// CHECK-LPAD-NEXT:  %[[sel:.+]] = load i32, ptr %ehselector.slot, align 4
+// CHECK-LPAD-NEXT:  %[[val1:.+]] = insertvalue { ptr, i32 } poison, ptr %[[exn]], 0
+// CHECK-LPAD-NEXT:  %[[val2:.+]] = insertvalue { ptr, i32 } %[[val1]], i32 %[[sel]], 1
+// CHECK-LPAD-NEXT:  resume { ptr, i32 } %[[val2]]

diff  --git a/clang/test/CodeGenCoroutines/coro-gro-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-gro-exp-namespace.cpp
new file mode 100644
index 0000000000000..bdd2e1149bf0a
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-gro-exp-namespace.cpp
@@ -0,0 +1,76 @@
+// Verifies lifetime of __gro local variable
+// Verify that coroutine promise and allocated memory are freed up on exception.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct GroType {
+  ~GroType();
+  operator int() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<int> {
+  struct promise_type {
+    GroType get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    promise_type();
+    ~promise_type();
+    void unhandled_exception() noexcept;
+  };
+};
+
+struct Cleanup {
+  ~Cleanup();
+};
+void doSomething() noexcept;
+
+// CHECK: define{{.*}} i32 @_Z1fv(
+int f() {
+  // CHECK: %[[RetVal:.+]] = alloca i32
+
+  // CHECK: %[[Size:.+]] = call i64 @llvm.coro.size.i64()
+  // CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef %[[Size]])
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeC1Ev(
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type17get_return_objectEv(ptr sret(%struct.GroType) align {{[0-9]+}} %[[GRO:.+]],
+  // CHECK: %[[Conv:.+]] = call noundef i32 @_ZN7GroTypecviEv({{.*}}[[GRO]]
+  // CHECK: store i32 %[[Conv]], ptr %[[RetVal]]
+
+  Cleanup cleanup;
+  doSomething();
+  co_return;
+
+  // CHECK: call void @_Z11doSomethingv(
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type11return_voidEv(
+  // CHECK: call void @_ZN7CleanupD1Ev(
+
+  // Destroy promise and free the memory.
+
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeD1Ev(
+  // CHECK: %[[Mem:.+]] = call ptr @llvm.coro.free(
+  // CHECK: call void @_ZdlPv(ptr noundef %[[Mem]])
+
+  // CHECK: coro.ret:
+  // CHECK:   %[[LoadRet:.+]] = load i32, ptr %[[RetVal]]
+  // CHECK:   ret i32 %[[LoadRet]]
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-gro2-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-gro2-exp-namespace.cpp
new file mode 100644
index 0000000000000..10c606450d5bf
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-gro2-exp-namespace.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+namespace std {
+
+struct nothrow_t {};
+constexpr nothrow_t nothrow = {};
+
+} // end namespace std
+
+// Required when get_return_object_on_allocation_failure() is defined by
+// the promise.
+void *operator new(__SIZE_TYPE__ __sz, const std::nothrow_t &) noexcept;
+void operator delete(void *__p, const std::nothrow_t &)noexcept;
+
+template <class RetObject>
+struct promise_type {
+  RetObject get_return_object();
+  suspend_always initial_suspend();
+  suspend_never final_suspend() noexcept;
+  void return_void();
+  static void unhandled_exception();
+};
+
+struct coro {
+  using promise_type = promise_type<coro>;
+  coro(coro const &);
+  struct Impl;
+  Impl *impl;
+};
+
+// Verify that the RVO is applied.
+// CHECK-LABEL: define{{.*}} void @_Z1fi(ptr noalias sret(%struct.coro) align 8 %agg.result, i32 noundef %0)
+coro f(int) {
+  // CHECK: %call = call noalias noundef nonnull ptr @_Znwm(
+  // CHECK-NEXT: br label %[[CoroInit:.*]]
+
+  // CHECK: {{.*}}[[CoroInit]]:
+  // CHECK: call void @{{.*get_return_objectEv}}(ptr sret(%struct.coro) align 8 %agg.result
+  co_return;
+}
+
+template <class RetObject>
+struct promise_type_with_on_alloc_failure {
+  static RetObject get_return_object_on_allocation_failure();
+  RetObject get_return_object();
+  suspend_always initial_suspend();
+  suspend_never final_suspend() noexcept;
+  void return_void();
+  static void unhandled_exception();
+};
+
+struct coro_two {
+  using promise_type = promise_type_with_on_alloc_failure<coro_two>;
+  coro_two(coro_two const &);
+  struct Impl;
+  Impl *impl;
+};
+
+// Verify that the NRVO is applied to the Gro object.
+// CHECK-LABEL: define{{.*}} void @_Z1hi(ptr noalias sret(%struct.coro_two) align 8 %agg.result, i32 noundef %0)
+coro_two h(int) {
+
+  // CHECK: %call = call noalias noundef ptr @_ZnwmRKSt9nothrow_t
+  // CHECK-NEXT: %[[CheckNull:.*]] = icmp ne ptr %call, null
+  // CHECK-NEXT: br i1 %[[CheckNull]], label %[[InitOnSuccess:.*]], label %[[InitOnFailure:.*]]
+
+  // CHECK: {{.*}}[[InitOnFailure]]:
+  // CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(ptr sret(%struct.coro_two) align 8 %agg.result
+  // CHECK-NEXT: br label %[[RetLabel:.*]]
+
+  // CHECK: {{.*}}[[InitOnSuccess]]:
+  // CHECK: call void @{{.*get_return_objectEv}}(ptr sret(%struct.coro_two) align 8 %agg.result
+
+  // CHECK: [[RetLabel]]:
+  // CHECK-NEXT: ret void
+  co_return;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-lambda-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-lambda-exp-namespace.cpp
new file mode 100644
index 0000000000000..2c9c446be0806
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-lambda-exp-namespace.cpp
@@ -0,0 +1,61 @@
+// Verify that we synthesized the coroutine for a lambda inside of a function template.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename R, typename... T> struct coroutine_traits {
+  using promise_type = typename R::promise_type;
+};
+
+template <class Promise = void> struct coroutine_handle;
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+template <class Promise> struct coroutine_handle : coroutine_handle<void> {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct Task {
+  struct promise_type {
+    Task get_return_object();
+    void return_void() {}
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception() noexcept;
+  };
+};
+
+template <typename _AwrT> auto SyncAwait(_AwrT &&A) {
+  if (!A.await_ready()) {
+    auto AwaitAsync = [&]() -> Task {
+      try {
+        (void)(co_await A);
+      } catch (...) {
+      }
+    };
+    Task t = AwaitAsync();
+  }
+  return A.await_resume();
+}
+
+void f() {
+  suspend_always test;
+  SyncAwait(test);
+}
+
+// Verify that we synthesized the coroutine for a lambda inside SyncAwait
+// CHECK-LABEL: define linkonce_odr void @_ZZ9SyncAwaitIR14suspend_alwaysEDaOT_ENKUlvE_clEv(
+//   CHECK: alloca %"struct.Task::promise_type"
+//   CHECK: call token @llvm.coro.id(
+//   CHECK: call i8 @llvm.coro.suspend(
+//   CHECK: call i1 @llvm.coro.end(

diff  --git a/clang/test/CodeGenCoroutines/coro-newpm-pipeline-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-newpm-pipeline-exp-namespace.cpp
new file mode 100644
index 0000000000000..8dcf59cb6f911
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-newpm-pipeline-exp-namespace.cpp
@@ -0,0 +1,45 @@
+// Tests that coroutine passes are added to and run by the new pass manager
+// pipeline, at -O0 and above.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null \
+// RUN:   -fdebug-pass-manager -fcoroutines-ts \
+// RUN:   -O0 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null \
+// RUN:   -fdebug-pass-manager -fcoroutines-ts \
+// RUN:   -O1 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
+//
+// CHECK-ALL: Running pass:{{.*}}CoroEarlyPass
+//
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+//
+// CHECK-ALL: Running pass:{{.*}}CoroCleanupPass
+
+namespace std {
+namespace experimental {
+
+struct handle {};
+
+struct awaitable {
+  bool await_ready() noexcept { return false; }
+  void await_suspend(handle) noexcept {}
+  bool await_resume() noexcept { return true; }
+};
+
+template <typename T> struct coroutine_handle {
+  static handle from_address(void *address) noexcept { return {}; }
+};
+
+template <typename T = void> struct coroutine_traits {
+  struct promise_type {
+    awaitable initial_suspend() { return {}; }
+    awaitable final_suspend() noexcept { return {}; }
+    void return_void() {}
+    T get_return_object() { return T(); }
+    void unhandled_exception() {}
+  };
+};
+} // namespace experimental
+} // namespace std
+
+void foo() { co_return; }

diff  --git a/clang/test/CodeGenCoroutines/coro-params-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-params-exp-namespace.cpp
new file mode 100644
index 0000000000000..84c3e67d5dac7
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-params-exp-namespace.cpp
@@ -0,0 +1,205 @@
+// Verifies that parameters are copied with move constructors
+// Verifies that parameter copies are destroyed
+// Vefifies that parameter copies are used in the body of the coroutine
+// Verifies that parameter copies are used to construct the promise type, if that type has a matching constructor
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
+  struct promise_type {
+    void get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    promise_type();
+    ~promise_type() noexcept;
+    void unhandled_exception() noexcept;
+  };
+};
+
+// TODO: Not supported yet
+struct CopyOnly {
+  int val;
+  CopyOnly(const CopyOnly &) noexcept;
+  CopyOnly(CopyOnly &&) = delete;
+  ~CopyOnly();
+};
+
+struct MoveOnly {
+  int val;
+  MoveOnly(const MoveOnly &) = delete;
+  MoveOnly(MoveOnly &&) noexcept;
+  ~MoveOnly();
+};
+
+struct MoveAndCopy {
+  int val;
+  MoveAndCopy(const MoveAndCopy &) noexcept;
+  MoveAndCopy(MoveAndCopy &&) noexcept;
+  ~MoveAndCopy();
+};
+
+void consume(int, int, int) noexcept;
+
+// TODO: Add support for CopyOnly params
+// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy(i32 noundef %val, %struct.MoveOnly* noundef %[[MoParam:.+]], %struct.MoveAndCopy* noundef %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*
+void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
+  // CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly,
+  // CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy,
+  // CHECK: store i32 %val, i32* %[[ValAddr:.+]]
+
+  // CHECK: call i8* @llvm.coro.begin(
+  // CHECK: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* {{[^,]*}} %[[MoCopy]], %struct.MoveOnly* noundef nonnull align 4 dereferenceable(4) %[[MoParam]])
+  // CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]], %struct.MoveAndCopy* noundef nonnull align 4 dereferenceable(4) %[[McParam]]) #
+  // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
+
+  // CHECK: call void @_ZN14suspend_always12await_resumeEv(
+  // CHECK: %[[IntParam:.+]] = load i32, i32* %{{.*}}
+  // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0
+  // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]]
+  // CHECK: %[[McGep:.+]] =  getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0
+  // CHECK: %[[McVal:.+]] = load i32, i32* %[[McGep]]
+  // CHECK: call void @_Z7consumeiii(i32 noundef %[[IntParam]], i32 noundef %[[MoVal]], i32 noundef %[[McVal]])
+
+  consume(val, moParam.val, mcParam.val);
+  co_return;
+
+  // Skip to final suspend:
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
+  // CHECK: call void @_ZN14suspend_always12await_resumeEv(
+
+  // Destroy promise, then parameter copies:
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* {{[^,]*}} %__promise)
+  // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(
+  // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]])
+  // CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(
+  // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(%struct.MoveOnly* {{[^,]*}} %[[MoCopy]]
+  // CHECK-NEXT: bitcast %struct.MoveOnly* %[[MoCopy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(
+  // CHECK-NEXT: bitcast i32* %{{.+}} to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(
+  // CHECK-NEXT: call i8* @llvm.coro.free(
+}
+
+// CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(%struct.A* noundef %x, %struct.B* noundef %0, %struct.B* noundef %y)
+template <typename T, typename U>
+void dependent_params(T x, U, U y) {
+  // CHECK: %[[x_copy:.+]] = alloca %struct.A,
+  // CHECK-NEXT: %[[unnamed_copy:.+]] = alloca %struct.B
+  // CHECK-NEXT: %[[y_copy:.+]] = alloca %struct.B
+
+  // CHECK: call i8* @llvm.coro.begin
+  // CHECK-NEXT: bitcast %struct.A* %[[x_copy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: call void @_ZN1AC1EOS_(%struct.A* {{[^,]*}} %[[x_copy]], %struct.A* noundef nonnull align 4 dereferenceable(512) %x)
+  // CHECK-NEXT: bitcast %struct.B* %[[unnamed_copy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* {{[^,]*}} %[[unnamed_copy]], %struct.B* noundef nonnull align 4 dereferenceable(512) %0)
+  // CHECK-NEXT: bitcast %struct.B* %[[y_copy]] to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* {{[^,]*}} %[[y_copy]], %struct.B* noundef nonnull align 4 dereferenceable(512) %y)
+  // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, A, B, B>::promise_type"* %__promise to i8*
+  // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+  // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJv1A1BS2_EE12promise_typeC1Ev(
+
+  co_return;
+}
+
+struct A {
+  int WontFitIntoRegisterForSure[128];
+  A();
+  A(A &&)
+  noexcept;
+  ~A();
+};
+
+struct B {
+  int WontFitIntoRegisterForSure[128];
+  B();
+  B(B &&)
+  noexcept;
+  ~B();
+};
+
+void call_dependent_params() {
+  dependent_params(A{}, B{}, B{});
+}
+
+// Test that, when the promise type has a constructor whose signature matches
+// that of the coroutine function, that constructor is used. This is an
+// experimental feature that will be proposed for the Coroutines TS.
+
+struct promise_matching_constructor {};
+
+template <>
+struct std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double> {
+  struct promise_type {
+    promise_type(promise_matching_constructor, int, float, double) {}
+    promise_type() = delete;
+    void get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception() {}
+  };
+};
+
+// CHECK-LABEL: void @_Z38coroutine_matching_promise_constructor28promise_matching_constructorifd(i32 noundef %0, float noundef %1, double noundef %2)
+void coroutine_matching_promise_constructor(promise_matching_constructor, int, float, double) {
+  // CHECK: %[[INT:.+]] = load i32, i32* %5, align 4
+  // CHECK: %[[FLOAT:.+]] = load float, float* %6, align 4
+  // CHECK: %[[DOUBLE:.+]] = load double, double* %7, align 8
+  // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double>::promise_type"* {{[^,]*}} %__promise, i32 noundef %[[INT]], float noundef %[[FLOAT]], double noundef %[[DOUBLE]])
+  co_return;
+}
+
+struct some_class;
+
+struct method {};
+
+template <typename... Args> struct std::experimental::coroutine_traits<method, Args...> {
+  struct promise_type {
+    promise_type(some_class &, float);
+    method get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void return_void();
+    void unhandled_exception();
+  };
+};
+
+struct some_class {
+  method good_coroutine_calls_custom_constructor(float);
+};
+
+// CHECK-LABEL: define{{.*}} void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(%struct.some_class*
+method some_class::good_coroutine_calls_custom_constructor(float) {
+  // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES3_f(%"struct.std::experimental::coroutine_traits<method, some_class &, float>::promise_type"* {{[^,]*}} %__promise, %struct.some_class* noundef nonnull align 1 dereferenceable(1) %{{.+}}, float
+  co_return;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-promise-dtor-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-promise-dtor-exp-namespace.cpp
new file mode 100644
index 0000000000000..30b655c03bb2b
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-promise-dtor-exp-namespace.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+// -triple=x86_64-unknown-linux-gnu
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct coro_t {
+  void *p;
+  ~coro_t();
+  struct promise_type {
+    coro_t get_return_object();
+    coro::suspend_never initial_suspend();
+    coro::suspend_never final_suspend() noexcept;
+    void return_void();
+    promise_type();
+    ~promise_type();
+    void unhandled_exception();
+  };
+};
+
+struct Cleanup {
+  ~Cleanup();
+};
+void may_throw();
+
+coro_t f() {
+  Cleanup cleanup;
+  may_throw();
+  co_return;
+}
+
+// CHECK-LABEL: define dso_local void @"?f@@YA?AUcoro_t@@XZ"(
+
+// CHECK:  invoke noundef ptr @"??0promise_type at coro_t@@QEAA at XZ"(
+// CHECK:  invoke void @"?get_return_object at promise_type@coro_t@@QEAA?AU2 at XZ"(
+
+// CHECK:  call void @"??1promise_type at coro_t@@QEAA at XZ"

diff  --git a/clang/test/CodeGenCoroutines/coro-ret-void-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-ret-void-exp-namespace.cpp
new file mode 100644
index 0000000000000..44c09616097f8
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-ret-void-exp-namespace.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct coro1 {
+  struct promise_type {
+    coro1 get_return_object();
+    coro::suspend_never initial_suspend();
+    coro::suspend_never final_suspend() noexcept;
+    void return_void();
+  };
+};
+
+coro1 f() {
+  co_await coro::suspend_never{};
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z1fv(
+// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(ptr
+// CHECK: call void @_ZN5coro112promise_type11return_voidEv(ptr {{[^,]*}} %__promise)
+
+struct A {
+  A();
+  ~A();
+};
+
+coro1 f2() {
+  co_return(void) A{};
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z2f2v(
+// CHECK: call void @_ZN1AC1Ev(ptr {{[^,]*}} %[[AVar:.*]])
+// CHECK-NEXT: call void @_ZN1AD1Ev(ptr {{[^,]*}} %[[AVar]])
+// CHECK-NEXT: call void @_ZN5coro112promise_type11return_voidEv(ptr
+
+struct coro2 {
+  struct promise_type {
+    coro2 get_return_object();
+    coro::suspend_never initial_suspend();
+    coro::suspend_never final_suspend() noexcept;
+    void return_value(int);
+  };
+};
+
+coro2 g() {
+  co_return 42;
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z1gv(
+// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(ptr
+// CHECK: call void @_ZN5coro212promise_type12return_valueEi(ptr {{[^,]*}} %__promise, i32 noundef 42)

diff  --git a/clang/test/CodeGenCoroutines/coro-return-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-return-exp-namespace.cpp
new file mode 100644
index 0000000000000..39de61067e2c1
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-return-exp-namespace.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++1z -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+  struct promise_type {
+    void get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+  // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<void>::promise_type"
+  // CHECK: %call = call noalias noundef nonnull ptr @_Znwm(
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv(ptr {{[^,]*}} %__promise)
+  // CHECK: call void @_ZdlPv
+  co_return;
+}
+
+template <>
+struct std::experimental::coroutine_traits<int> {
+  struct promise_type {
+    int get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void return_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" int f1() {
+  // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<int>::promise_type"
+  // CHECK: %call = call noalias noundef nonnull ptr @_Znwm(
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type12return_valueEi(ptr {{[^,]*}} %__promise, i32 noundef 42)
+  // CHECK: call void @_ZdlPv
+  co_return 42;
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist-exp-namespace.cpp
new file mode 100644
index 0000000000000..fbcab6386103c
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist-exp-namespace.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++1z -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+template <typename a>
+struct b { b(int, a); };
+template <typename, typename = int>
+struct c {};
+namespace experimental {
+template <typename d>
+struct coroutine_traits : d {};
+template <typename = void>
+struct coroutine_handle;
+template <>
+struct coroutine_handle<> {};
+template <typename>
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *) noexcept;
+};
+struct e {
+  int await_ready();
+  void await_suspend(coroutine_handle<>);
+  void await_resume();
+};
+} // namespace experimental
+} // namespace std
+template <typename ag>
+auto ah(ag) { return ag().ah(0); }
+template <typename>
+struct f;
+struct g {
+  struct h {
+    int await_ready() noexcept;
+    template <typename al>
+    void await_suspend(std::experimental::coroutine_handle<al>) noexcept;
+    void await_resume() noexcept;
+  };
+  std::experimental::e initial_suspend();
+  h final_suspend() noexcept;
+  template <typename ag>
+  auto await_transform(ag) { return ah(ag()); }
+};
+struct j : g {
+  f<std::b<std::c<int, int>>> get_return_object();
+  void return_value(std::b<std::c<int, int>>);
+  void unhandled_exception();
+};
+struct k {
+  k(std::experimental::coroutine_handle<>);
+  int await_ready();
+};
+template <typename am>
+struct f {
+  using promise_type = j;
+  std::experimental::coroutine_handle<> ar;
+  struct l : k {
+    using at = k;
+    l(std::experimental::coroutine_handle<> m) : at(m) {}
+    void await_suspend(std::experimental::coroutine_handle<>);
+  };
+  struct n : l {
+    n(std::experimental::coroutine_handle<> m) : l(m) {}
+    am await_resume();
+  };
+  auto ah(int) { return n(ar); }
+};
+template <typename am, typename av, typename aw>
+auto ax(std::c<am, av>, aw) -> f<std::c<int, aw>>;
+template <typename>
+struct J { static f<std::b<std::c<int, int>>> bo(); };
+// CHECK-LABEL: _ZN1JIiE2boEv(
+template <typename bc>
+f<std::b<std::c<int, int>>> J<bc>::bo() {
+  std::c<int> bu;
+  int bw(0);
+  // CHECK: void @_ZN1j12return_valueESt1bISt1cIiiEE(ptr {{[^,]*}} %__promise)
+  co_return {0, co_await ax(bu, bw)};
+}
+void bh() {
+  auto cn = [] { J<int>::bo; };
+  cn();
+}

diff  --git a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01-exp-namespace.cpp
new file mode 100644
index 0000000000000..c60c2e0e271a7
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01-exp-namespace.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O0 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+// RUN: %clang -fcoroutines-ts -std=c++14 -O0 -emit-llvm -c  %s -o %t -Xclang -disable-llvm-passes && %clang -c %t
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+    detached_task get_return_object() noexcept {
+      return detached_task{coro::coroutine_handle<promise_type>::from_promise(*this)};
+    }
+
+    void return_void() noexcept {}
+
+    struct final_awaiter {
+      bool await_ready() noexcept { return false; }
+      coro::coroutine_handle<> await_suspend(coro::coroutine_handle<promise_type> h) noexcept {
+        h.destroy();
+        return {};
+      }
+      void await_resume() noexcept {}
+    };
+
+    void unhandled_exception() noexcept {}
+
+    final_awaiter final_suspend() noexcept { return {}; }
+
+    coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+    if (coro_) {
+      coro_.destroy();
+      coro_ = {};
+    }
+  }
+
+  void start() && {
+    auto tmp = coro_;
+    coro_ = {};
+    tmp.resume();
+  }
+
+  coro::coroutine_handle<promise_type> coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address is contained within single basic block, and hence does not live across suspension points.
+// CHECK-LABEL: final.suspend:
+// CHECK:         %{{.+}} = call token @llvm.coro.save(ptr null)
+// CHECK:         call void @llvm.lifetime.start.p0(i64 8, ptr %[[HDL:.+]])
+// CHECK:         %[[CALL:.+]] = call ptr @_ZN13detached_task12promise_type13final_awaiter13await_suspendENSt12experimental13coroutines_v116coroutine_handleIS0_EE(
+// CHECK:         %[[HDL_CAST2:.+]] = getelementptr inbounds %"struct.std::experimental::coroutines_v1::coroutine_handle.0", ptr %[[HDL]], i32 0, i32 0
+// CHECK:         store ptr %[[CALL]], ptr %[[HDL_CAST2]], align 8
+// CHECK:         %[[HDL_TRANSFER:.+]] = call ptr @_ZNKSt12experimental13coroutines_v116coroutine_handleIvE7addressEv(ptr nonnull align 8 dereferenceable(8) %[[HDL]])
+// CHECK:         call void @llvm.lifetime.end.p0(i64 8, ptr %[[HDL]])
+// CHECK:         call void @llvm.coro.resume(ptr %[[HDL_TRANSFER]])

diff  --git a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02-exp-namespace.cpp
new file mode 100644
index 0000000000000..c9a496a1b747a
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02-exp-namespace.cpp
@@ -0,0 +1,122 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct Task {
+  struct promise_type {
+    Task get_return_object() noexcept {
+      return Task{coro::coroutine_handle<promise_type>::from_promise(*this)};
+    }
+
+    void return_void() noexcept {}
+
+    struct final_awaiter {
+      bool await_ready() noexcept { return false; }
+      coro::coroutine_handle<> await_suspend(coro::coroutine_handle<promise_type> h) noexcept {
+        h.destroy();
+        return {};
+      }
+      void await_resume() noexcept {}
+    };
+
+    void unhandled_exception() noexcept {}
+
+    final_awaiter final_suspend() noexcept { return {}; }
+
+    coro::suspend_always initial_suspend() noexcept { return {}; }
+
+    template <typename Awaitable>
+    auto await_transform(Awaitable &&awaitable) {
+      return awaitable.co_viaIfAsync();
+    }
+  };
+
+  using handle_t = coro::coroutine_handle<promise_type>;
+
+  class Awaiter {
+  public:
+    explicit Awaiter(handle_t coro) noexcept;
+    Awaiter(Awaiter &&other) noexcept;
+    Awaiter(const Awaiter &) = delete;
+    ~Awaiter();
+
+    bool await_ready() noexcept { return false; }
+    handle_t await_suspend(coro::coroutine_handle<> continuation) noexcept;
+    void await_resume();
+
+  private:
+    handle_t coro_;
+  };
+
+  Task(handle_t coro) noexcept : coro_(coro) {}
+
+  handle_t coro_;
+
+  Task(const Task &t) = delete;
+  Task(Task &&t) noexcept;
+  ~Task();
+  Task &operator=(Task t) noexcept;
+
+  Awaiter co_viaIfAsync();
+};
+
+static Task foo() {
+  co_return;
+}
+
+Task bar() {
+  auto mode = 2;
+  switch (mode) {
+  case 1:
+    co_await foo();
+    break;
+  case 2:
+    co_await foo();
+    break;
+  default:
+    break;
+  }
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z3barv
+// CHECK:         %[[MODE:.+]] = load i32, ptr %mode
+// CHECK-NEXT:    switch i32 %[[MODE]], label %{{.+}} [
+// CHECK-NEXT:      i32 1, label %[[CASE1:.+]]
+// CHECK-NEXT:      i32 2, label %[[CASE2:.+]]
+// CHECK-NEXT:    ]
+
+// CHECK:       [[CASE1]]:
+// CHECK:         br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
+// CHECK:       [[CASE1_AWAIT_SUSPEND]]:
+// CHECK-NEXT:    %{{.+}} = call token @llvm.coro.save(ptr null)
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 8, ptr %[[TMP1:.+]])
+
+// CHECK:    call void @llvm.lifetime.end.p0(i64 8, ptr %[[TMP1]])
+// CHECK-NEXT:    call void @llvm.coro.resume
+// CHECK-NEXT:    %{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:    switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:      i8 0, label %[[CASE1_AWAIT_READY]]
+// CHECK-NEXT:      i8 1, label %[[CASE1_AWAIT_CLEANUP:.+]]
+// CHECK-NEXT:    ]
+// CHECK:       [[CASE1_AWAIT_CLEANUP]]:
+// make sure that the awaiter eventually gets cleaned up.
+// CHECK:         call void @{{.+Awaiter.+}}
+
+// CHECK:       [[CASE2]]:
+// CHECK:         br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
+// CHECK:       [[CASE2_AWAIT_SUSPEND]]:
+// CHECK-NEXT:    %{{.+}} = call token @llvm.coro.save(ptr null)
+// CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 8, ptr %[[TMP2:.+]])
+
+// CHECK:    call void @llvm.lifetime.end.p0(i64 8, ptr %[[TMP2]])
+// CHECK-NEXT:    call void @llvm.coro.resume
+// CHECK-NEXT:    %{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:    switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:      i8 0, label %[[CASE2_AWAIT_READY]]
+// CHECK-NEXT:      i8 1, label %[[CASE2_AWAIT_CLEANUP:.+]]
+// CHECK-NEXT:    ]
+// CHECK:       [[CASE2_AWAIT_CLEANUP]]:
+// make sure that the awaiter eventually gets cleaned up.
+// CHECK:         call void @{{.+Awaiter.+}}

diff  --git a/clang/test/CodeGenCoroutines/coro-unhandled-exception-exp-namespace.cpp b/clang/test/CodeGenCoroutines/coro-unhandled-exception-exp-namespace.cpp
new file mode 100644
index 0000000000000..0bce7b1720dae
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-unhandled-exception-exp-namespace.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s
+
+#include "Inputs/coroutine-exp-namespace.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+namespace std {
+using exception_ptr = int;
+exception_ptr current_exception();
+} // namespace std
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object() {
+      coro::coroutine_handle<promise_type>{};
+      return {};
+    }
+    coro::suspend_never initial_suspend() { return {}; }
+    coro::suspend_never final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception() noexcept;
+  };
+};
+
+struct Cleanup {
+  ~Cleanup();
+};
+void may_throw();
+
+coro_t f() {
+  Cleanup x;
+  may_throw();
+  co_return;
+}
+
+// CHECK: @"?f@@YA?AUcoro_t@@XZ"(
+// CHECK:   invoke void @"?may_throw@@YAXXZ"()
+// CHECK:       to label %{{.+}} unwind label %[[EHCLEANUP:.+]]
+// CHECK: [[EHCLEANUP]]:
+// CHECK:   %[[INNERPAD:.+]] = cleanuppad within none []
+// CHECK:   call void @"??1Cleanup@@QEAA at XZ"(
+// CHECK:   cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]]
+// CHECK: [[CATCHSW]]:
+// CHECK:   %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label
+// CHECK: [[CATCH]]:
+// CHECK:   %[[CATCHTOK:.+]] = catchpad within [[CATCHSWTOK:.+]]
+// CHECK:   call void @"?unhandled_exception at promise_type@coro_t@@QEAAXXZ"
+// CHECK:   catchret from %[[CATCHTOK]] to label %[[CATCHRETDEST:.+]]
+// CHECK: [[CATCHRETDEST]]:
+// CHECK-NEXT: br label %[[TRYCONT:.+]]
+// CHECK: [[TRYCONT]]:
+// CHECK-NEXT: br label %[[COROFIN:.+]]
+// CHECK: [[COROFIN]]:
+// CHECK-NEXT: bitcast %"struct.std::experimental::coroutines_v1::suspend_never"* %{{.+}} to i8*
+// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
+// CHECK-NEXT: call void @"?final_suspend at promise_type@coro_t@@QEAA?AUsuspend_never at coroutines_v1@experimental at std@@XZ"(
+
+// CHECK-LPAD: @_Z1fv(
+// CHECK-LPAD:   invoke void @_Z9may_throwv()
+// CHECK-LPAD:       to label %[[CONT:.+]] unwind label %[[CLEANUP:.+]]
+// CHECK-LPAD: [[CLEANUP]]:
+// CHECK-LPAD:   call void @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %x) #2
+// CHECK-LPAD:   br label %[[CATCH:.+]]
+
+// CHECK-LPAD: [[CATCH]]:
+// CHECK-LPAD:    call i8* @__cxa_begin_catch
+// CHECK-LPAD:    call void @_ZN6coro_t12promise_type19unhandled_exceptionEv(%"struct.coro_t::promise_type"* {{[^,]*}} %__promise) #2
+// CHECK-LPAD:    invoke void @__cxa_end_catch()
+// CHECK-LPAD-NEXT:  to label %[[CATCHRETDEST:.+]] unwind label
+// CHECK-LPAD: [[CATCHRETDEST]]:
+// CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]]
+// CHECK-LPAD: [[TRYCONT]]:
+// CHECK-LPAD: br label %[[COROFIN:.+]]
+// CHECK-LPAD: [[COROFIN]]:
+// CHECK-LPAD-NEXT: bitcast %"struct.std::experimental::coroutines_v1::suspend_never"* %{{.+}} to i8*
+// CHECK-LPAD-NEXT: call void @llvm.lifetime.start.p0i8(
+// CHECK-LPAD-NEXT: call void @_ZN6coro_t12promise_type13final_suspendEv(

diff  --git a/clang/test/CodeGenCoroutines/microsoft-abi-operator-coawait-exp-namespace.cpp b/clang/test/CodeGenCoroutines/microsoft-abi-operator-coawait-exp-namespace.cpp
new file mode 100644
index 0000000000000..33818c5d2fd3a
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/microsoft-abi-operator-coawait-exp-namespace.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc18.0.0 -fcoroutines-ts -emit-llvm %s -o - -std=c++14 -disable-llvm-passes | FileCheck %s
+struct no_suspend {
+  bool await_ready() { return true; }
+  template <typename F> void await_suspend(F) {}
+  void await_resume() {}
+};
+
+struct A {
+  no_suspend operator co_await() { return {}; }
+};
+
+struct B {};
+
+no_suspend operator co_await(B const &) { return {}; }
+
+// CHECK-LABEL: f(
+extern "C" void f() {
+  A a;
+  B b;
+  // CHECK: call void @"??__LA@@QEAA?AUno_suspend@@XZ"(
+  a.operator co_await();
+  // CHECK-NEXT: call i8 @"??__L at YA?AUno_suspend@@AEBUB@@@Z"(
+  operator co_await(b);
+}

diff  --git a/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp b/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp
new file mode 100644
index 0000000000000..9db3f0138d460
--- /dev/null
+++ b/clang/test/SemaCXX/co_await-range-for-exp-namespace.cpp
@@ -0,0 +1,165 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN:    -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN:    -fblocks
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+template <class Begin>
+struct Awaiter {
+  bool await_ready();
+  void await_suspend(coroutine_handle<>);
+  Begin await_resume();
+};
+
+template <class Iter> struct BeginTag { BeginTag() = delete; };
+template <class Iter> struct IncTag { IncTag() = delete; };
+
+template <class Iter, bool Delete = false>
+struct CoawaitTag { CoawaitTag() = delete; };
+
+template <class T>
+struct Iter {
+  using value_type = T;
+  using reference = T &;
+  using pointer = T *;
+
+  IncTag<Iter> operator++();
+  reference operator*();
+  pointer operator->();
+};
+template <class T> bool operator==(Iter<T>, Iter<T>);
+template <class T> bool operator!=(Iter<T>, Iter<T>);
+
+template <class T>
+struct Range {
+  BeginTag<Iter<T>> begin();
+  Iter<T> end();
+};
+
+struct MyForLoopArrayAwaiter {
+  struct promise_type {
+    MyForLoopArrayAwaiter get_return_object() { return {}; }
+    void return_void();
+    void unhandled_exception();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    template <class T>
+    Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
+  };
+};
+MyForLoopArrayAwaiter g() {
+  int arr[10] = {0};
+  for co_await (auto i : arr) {} // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+  // expected-error at -1 {{call to deleted member function 'await_transform'}}
+  // expected-note at -2 {{'await_transform' implicitly required by 'co_await' here}}
+  // expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+}
+
+struct ForLoopAwaiterBadBeginTransform {
+  struct promise_type {
+    ForLoopAwaiterBadBeginTransform get_return_object();
+    void return_void();
+    void unhandled_exception();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+
+    template <class T>
+    Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
+
+    template <class T>
+    CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
+  };
+};
+ForLoopAwaiterBadBeginTransform bad_begin() {
+  Range<int> R;
+  for co_await (auto i : R) {}
+  // expected-error at -1 {{call to deleted member function 'await_transform'}}
+  // expected-note at -2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template <class Dummy>
+ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
+  Range<Dummy> R;
+  for co_await (auto i : R) {}
+  // expected-error at -1 {{call to deleted member function 'await_transform'}}
+  // expected-note at -2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
+
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
+// expected-note at -1 1+ {{explicitly deleted}}
+
+struct ForLoopAwaiterBadIncTransform {
+  struct promise_type {
+    ForLoopAwaiterBadIncTransform get_return_object();
+    void return_void();
+    void unhandled_exception();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+
+    template <class T>
+    Awaiter<T> await_transform(BeginTag<T> e);
+
+    template <class T>
+    CoawaitTag<T, true> await_transform(IncTag<T>);
+  };
+};
+ForLoopAwaiterBadIncTransform bad_inc_transform() {
+  Range<float> R;
+  for co_await (auto i : R) {}
+  // expected-error at -1 {{overload resolution selected deleted operator 'co_await'}}
+  // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
+}
+
+template <class Dummy>
+ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
+  Range<Dummy> R;
+  for co_await (auto i : R) {}
+  // expected-error at -1 {{overload resolution selected deleted operator 'co_await'}}
+  // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
+}
+template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
+
+// Ensure we mark and check the function as a coroutine even if it's
+// never instantiated.
+template <class T>
+constexpr void never_instant(T) {
+  static_assert(sizeof(T) != sizeof(T), "function should not be instantiated");
+  for co_await (auto i : foo(T{})) {}
+  // expected-error at -1 {{'co_await' cannot be used in a constexpr function}}
+}
+
+namespace NS {
+struct ForLoopAwaiterCoawaitLookup {
+  struct promise_type {
+    ForLoopAwaiterCoawaitLookup get_return_object();
+    void return_void();
+    void unhandled_exception();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    template <class T>
+    CoawaitTag<T, false> await_transform(BeginTag<T> e);
+    template <class T>
+    Awaiter<T> await_transform(IncTag<T>);
+  };
+};
+} // namespace NS
+using NS::ForLoopAwaiterCoawaitLookup;
+
+template <class T>
+ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
+  Range<T> R;
+  for co_await (auto i : R) {}
+  // expected-error at -1 {{no member named 'await_ready' in 'CoawaitTag<Iter<int>>'}}
+}
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
+
+// FIXME: This test should fail as well since the newly declared operator co_await
+// should not be found by lookup.
+namespace NS2 {
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
+}
+using NS2::operator co_await;
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);

diff  --git a/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp b/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp
new file mode 100644
index 0000000000000..6e302d6179878
--- /dev/null
+++ b/clang/test/SemaCXX/coreturn-eh-exp-namespace.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fcxx-exceptions -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wall -Wextra -Wno-error=unreachable-code
+
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
+
+struct awaitable {
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>); // FIXME: coroutine_handle
+  void await_resume();
+} a;
+
+struct object {
+  ~object() {}
+};
+
+struct promise_void_return_value {
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_value(object);
+};
+
+struct VoidTagReturnValue {
+  struct promise_type {
+    VoidTagReturnValue get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception();
+    void return_value(object);
+  };
+};
+
+template <typename T1>
+struct std::experimental::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
+
+VoidTagReturnValue test() {
+  object x = {};
+  try {
+    co_return {}; // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+    // expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+  } catch (...) {
+    throw;
+  }
+}

diff  --git a/clang/test/SemaCXX/coreturn-exp-namespace.cpp b/clang/test/SemaCXX/coreturn-exp-namespace.cpp
new file mode 100644
index 0000000000000..2c0f2842fcbe0
--- /dev/null
+++ b/clang/test/SemaCXX/coreturn-exp-namespace.cpp
@@ -0,0 +1,141 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wall -Wextra -Wno-error=unreachable-code
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
+
+struct awaitable {
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>); // FIXME: coroutine_handle
+  void await_resume();
+} a;
+
+struct promise_void {
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+struct promise_void_return_value {
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_value(int);
+};
+
+struct VoidTagNoReturn {
+  struct promise_type {
+    VoidTagNoReturn get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception();
+  };
+};
+
+struct VoidTagReturnValue {
+  struct promise_type {
+    VoidTagReturnValue get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception();
+    void return_value(int);
+  };
+};
+
+struct VoidTagReturnVoid {
+  struct promise_type {
+    VoidTagReturnVoid get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception();
+    void return_void();
+  };
+};
+
+struct promise_float {
+  float get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+struct promise_int {
+  int get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_value(int);
+  void unhandled_exception();
+};
+
+template <>
+struct std::experimental::coroutine_traits<void> { using promise_type = promise_void; };
+
+template <typename T1>
+struct std::experimental::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
+
+template <typename... T>
+struct std::experimental::coroutine_traits<float, T...> { using promise_type = promise_float; };
+
+template <typename... T>
+struct std::experimental::coroutine_traits<int, T...> { using promise_type = promise_int; };
+
+void test0() { co_await a; } // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+// expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+float test1() { co_await a; }
+
+int test2() {
+  co_await a;
+} // expected-warning {{non-void coroutine does not return a value}}
+
+int test2a(bool b) {
+  if (b)
+    co_return 42;
+} // expected-warning {{non-void coroutine does not return a value in all control paths}}
+
+int test3() {
+  co_await a;
+b:
+  goto b;
+}
+
+int test4() {
+  co_return 42;
+}
+
+void test5(int) {
+  co_await a;
+} // expected-warning {{non-void coroutine does not return a value}}
+
+void test6(int x) {
+  if (x)
+    co_return 42;
+} // expected-warning {{non-void coroutine does not return a value in all control paths}}
+
+void test7(int y) {
+  if (y)
+    co_return 42;
+  else
+    co_return 101;
+}
+
+VoidTagReturnVoid test8() {
+  co_await a;
+}
+
+VoidTagReturnVoid test9(bool b) {
+  if (b)
+    co_return;
+}
+
+VoidTagReturnValue test10() {
+  co_await a;
+} // expected-warning {{non-void coroutine does not return a value}}
+
+VoidTagReturnValue test11(bool b) {
+  if (b)
+    co_return 42;
+} // expected-warning {{non-void coroutine does not return a value in all control paths}}

diff  --git a/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp
new file mode 100644
index 0000000000000..e50e90b8df4f2
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-final-suspend-noexcept-exp-namespace.cpp
@@ -0,0 +1,106 @@
+// This file contains references to sections of the Coroutines TS, which can be
+// found at http://wg21.link/coroutines.
+
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result
+
+namespace std {
+namespace experimental {
+template <class Ret, typename... T>
+struct coroutine_traits { using promise_type = typename Ret::promise_type; };
+// expected-note at -1{{declared here}}
+
+template <class Promise = void>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *);
+  void *address() const noexcept;
+};
+template <>
+struct coroutine_handle<void> {
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>);
+  void *address() const noexcept;
+};
+
+struct suspend_always {
+  bool await_ready() { return false; }      // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_suspend(coroutine_handle<>) {} // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_resume() {}                    // expected-note 2 {{must be declared with 'noexcept'}}
+  ~suspend_always() noexcept(false);        // expected-note 2 {{must be declared with 'noexcept'}}
+};
+} // namespace experimental
+} // namespace std
+
+using namespace std::experimental;
+
+struct A {
+  bool await_ready();
+  void await_resume();
+  template <typename F>
+  void await_suspend(F);
+};
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object();
+    suspend_always initial_suspend();
+    suspend_always final_suspend(); // expected-note 2 {{must be declared with 'noexcept'}}
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+coro_t f(int n) { // expected-error {{the expression 'co_await __promise.final_suspend()' is required to be non-throwing}}
+  A a{};
+  co_await a; // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+}
+
+template <typename T>
+coro_t f_dep(T n) { // expected-error {{the expression 'co_await __promise.final_suspend()' is required to be non-throwing}}
+  A a{};
+  co_await a;
+}
+
+void foo() {
+  f_dep<int>(5); // expected-note {{in instantiation of function template specialization 'f_dep<int>' requested here}}
+}
+
+struct PositiveFinalSuspend {
+  bool await_ready() noexcept;
+  coroutine_handle<> await_suspend(coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct correct_coro {
+  struct promise_type {
+    correct_coro get_return_object();
+    suspend_always initial_suspend();
+    PositiveFinalSuspend final_suspend() noexcept;
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+correct_coro f2(int n) {
+  co_return;
+}
+
+struct NegativeFinalSuspend {
+  bool await_ready() noexcept;
+  coroutine_handle<> await_suspend(coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+  ~NegativeFinalSuspend() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+};
+
+struct incorrect_coro {
+  struct promise_type {
+    incorrect_coro get_return_object();
+    suspend_always initial_suspend();
+    NegativeFinalSuspend final_suspend() noexcept;
+    void return_void();
+    static void unhandled_exception();
+  };
+};
+
+incorrect_coro f3(int n) { // expected-error {{the expression 'co_await __promise.final_suspend()' is required to be non-throwing}}
+  co_return;
+}

diff  --git a/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
new file mode 100644
index 0000000000000..97b4e687ed870
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-mixed-exp-namespace.cpp
@@ -0,0 +1,30 @@
+// This file is to test the mixed use of `std::experimental::coroutine*` and `std::coroutine*`
+// wouldn't make the compiler to crash and emit the diagnostic message correctly.
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+#include "Inputs/std-coroutine-exp-namespace.h"
+#include "Inputs/std-coroutine.h" // Second
+
+struct my_awaitable {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<> coro) noexcept;
+  void await_resume() noexcept;
+};
+
+struct promise_void {
+  void get_return_object();
+  my_awaitable initial_suspend();
+  my_awaitable final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+template <>
+struct std::coroutine_traits<void> { using promise_type = promise_void; };
+
+void test() {
+  co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
+  // expected-warning at -1{{support for 'std::experimental::coroutine_traits' will be removed}}
+  // expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+  // expected-note at Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
+}

diff  --git a/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
new file mode 100644
index 0000000000000..7fec83fdd7c28
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-mixed2-exp-namespace.cpp
@@ -0,0 +1,31 @@
+// This file is to test the mixed use of `std::experimental::coroutine_traits` and `std::coroutine_traits`
+// which is similar to coroutine-mixed-exp-namespace. This file tests the relative order of
+// included header wouldn't affect the diagnostic messages.
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+#include "Inputs/std-coroutine.h" // First
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+struct my_awaitable {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<> coro) noexcept;
+  void await_resume() noexcept;
+};
+
+struct promise_void {
+  void get_return_object();
+  my_awaitable initial_suspend();
+  my_awaitable final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+template <>
+struct std::coroutine_traits<void> { using promise_type = promise_void; };
+
+void test() {
+  co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
+  // expected-warning at -1{{support for 'std::experimental::coroutine_traits' will be removed}}
+  // expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+  // expected-note at Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
+}

diff  --git a/clang/test/SemaCXX/coroutine-mixed3-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed3-exp-namespace.cpp
new file mode 100644
index 0000000000000..b47f5f75ab99a
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-mixed3-exp-namespace.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+#include "Inputs/std-coroutine.h"
+
+namespace std::experimental {
+using std::coroutine_handle;
+using std::coroutine_traits; // expected-note{{declared here}}
+} // namespace std::experimental
+
+struct my_awaitable {
+  bool await_ready() noexcept;
+  void await_suspend(std::coroutine_handle<> coro) noexcept;
+  void await_resume() noexcept;
+};
+
+struct promise_void {
+  void get_return_object();
+  my_awaitable initial_suspend();
+  my_awaitable final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+template <>
+struct std::coroutine_traits<void> { using promise_type = promise_void; };
+
+void test() {
+  co_return;
+  // expected-warning at -1{{support for 'std::experimental::coroutine_traits' will be removed}}
+}

diff  --git a/clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
new file mode 100644
index 0000000000000..b09482d5b426b
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-mixed4-exp-namespace.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+#include "Inputs/std-coroutine.h"
+
+namespace std::experimental {
+// expected-note at +1{{declared here}}
+template <typename T> using coroutine_traits = std::coroutine_traits<T>;
+using std::coroutine_handle;
+} // namespace std::experimental
+
+struct my_awaitable {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<> coro) noexcept;
+  void await_resume() noexcept;
+};
+
+struct promise_void {
+  void get_return_object();
+  my_awaitable initial_suspend();
+  my_awaitable final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+template <>
+struct std::coroutine_traits<void> { using promise_type = promise_void; };
+
+void test() {
+  co_return; // expected-error {{mixed use of std and std::experimental namespaces for coroutine components}}
+  // expected-warning at -1{{support for 'std::experimental::coroutine_traits' will be removed}}
+  // expected-note at Inputs/std-coroutine.h:18 {{'coroutine_traits' declared here}}
+}

diff  --git a/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp
new file mode 100644
index 0000000000000..dd8efa1bffd41
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-rvo-exp-namespace.cpp
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -verify -std=c++17 -fcoroutines-ts -fsyntax-only %s
+
+namespace std::experimental {
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+
+template <class... Args>
+struct void_t_imp {
+  using type = void;
+};
+template <class... Args>
+using void_t = typename void_t_imp<Args...>::type;
+
+template <class T, class = void>
+struct traits_sfinae_base {};
+
+template <class T>
+struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
+  using promise_type = typename T::promise_type;
+};
+
+template <class Ret, class... Args>
+struct coroutine_traits : public traits_sfinae_base<Ret> {};
+// expected-note at -1{{declared here}}
+} // namespace std::experimental
+
+struct suspend_never {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct MoveOnly {
+  MoveOnly() = default;
+  MoveOnly(const MoveOnly &) = delete;
+  MoveOnly(MoveOnly &&) = default;
+};
+
+struct NoCopyNoMove {
+  NoCopyNoMove() = default;
+  NoCopyNoMove(const NoCopyNoMove &) = delete;
+};
+
+template <typename T>
+struct task {
+  struct promise_type {
+    auto initial_suspend() { return suspend_never{}; }
+    auto final_suspend() noexcept { return suspend_never{}; }
+    auto get_return_object() { return task{}; }
+    static void unhandled_exception() {}
+    void return_value(T &&value) {} // expected-note 4{{passing argument}}
+  };
+};
+
+task<NoCopyNoMove> local2val() {
+  NoCopyNoMove value;
+  co_return value; // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+}
+
+task<NoCopyNoMove &> local2ref() {
+  NoCopyNoMove value;
+  co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
+}
+
+// We need the move constructor for construction of the coroutine.
+task<MoveOnly> param2val(MoveOnly value) {
+  co_return value;
+}
+
+task<NoCopyNoMove> lvalue2val(NoCopyNoMove &value) {
+  co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
+}
+
+task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) {
+  co_return value;
+}
+
+task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) {
+  co_return value;
+}
+
+task<NoCopyNoMove &> rvalue2ref(NoCopyNoMove &&value) {
+  co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
+}
+
+struct To {
+  operator MoveOnly() &&;
+};
+task<MoveOnly> conversion_operator() {
+  To t;
+  co_return t;
+}
+
+struct Construct {
+  Construct(MoveOnly);
+};
+task<Construct> converting_constructor() {
+  MoveOnly w;
+  co_return w;
+}
+
+struct Derived : MoveOnly {};
+task<MoveOnly> derived2base() {
+  Derived result;
+  co_return result;
+}
+
+struct RetThis {
+  task<RetThis> foo() && {
+    co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}}
+  }
+};
+
+template <typename, typename>
+struct is_same { static constexpr bool value = false; };
+
+template <typename T>
+struct is_same<T, T> { static constexpr bool value = true; };
+
+template <typename T>
+struct generic_task {
+  struct promise_type {
+    auto initial_suspend() { return suspend_never{}; }
+    auto final_suspend() noexcept { return suspend_never{}; }
+    auto get_return_object() { return generic_task{}; }
+    static void unhandled_exception();
+    template <typename U>
+    void return_value(U &&value) {
+      static_assert(is_same<T, U>::value);
+    }
+  };
+};
+
+generic_task<MoveOnly> param2template(MoveOnly value) {
+  co_return value; // We should deduce U = MoveOnly.
+}
+
+generic_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) {
+  co_return value; // We should deduce U = NoCopyNoMove&.
+}

diff  --git a/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp
new file mode 100644
index 0000000000000..37d6975e1de50
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-seh-exp-namespace.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -triple x86_64-windows-msvc -fms-extensions
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
+// expected-note at -1{{declared here}}
+
+template <class Promise = void> struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+  static coroutine_handle from_address(void *) noexcept;
+  coroutine_handle() = default;
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+  struct promise_type {
+    void get_return_object() noexcept;
+    suspend_always initial_suspend() noexcept;
+    suspend_always final_suspend() noexcept;
+    void return_void() noexcept;
+    void unhandled_exception() noexcept;
+  };
+};
+
+void SEH_used() {
+  __try {      // expected-error {{cannot use SEH '__try' in a coroutine when C++ exceptions are enabled}}
+    co_return; // expected-note {{function is a coroutine due to use of 'co_return' here}}
+               // expected-warning at -1 {{support for 'std::experimental::coroutine_traits' will be removed}}
+  } __except (0) {
+  }
+}

diff  --git a/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp
new file mode 100644
index 0000000000000..f0f1cc573eff3
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-traits-undefined-template-exp-namespace.cpp
@@ -0,0 +1,20 @@
+// This file contains references to sections of the Coroutines TS, which can be
+// found at http://wg21.link/coroutines.
+
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result
+
+namespace std {
+namespace experimental {
+template <typename... T>
+struct coroutine_traits { // expected-note{{declared here}}
+  struct promise_type {};
+};
+
+template <> struct coroutine_traits<void>; // expected-note {{forward declaration of 'std::experimental::coroutine_traits<void>'}}
+} // namespace experimental
+} // namespace std
+
+void uses_forward_declaration() {
+  co_return; // expected-error {{this function cannot be a coroutine: missing definition of specialization 'coroutine_traits<void>'}}
+             // expected-warning at -1 {{support for 'std::experimental::coroutine_traits' will be removed}}
+}

diff  --git a/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp
new file mode 100644
index 0000000000000..bd5dced7f215b
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-unhandled_exception-warning-exp-namespace.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN:    -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN:    -fblocks -Wno-unreachable-code -Wno-unused-value
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN:    -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN:    -fblocks -Wno-unreachable-code -Wno-unused-value \
+// RUN:    -DDISABLE_WARNING -Wno-deprecated-experimental-coroutine -Wno-coroutine-missing-unhandled-exception
+
+#if __has_feature(cxx_exceptions)
+#error This test requires exceptions be disabled
+#endif
+
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
+
+#ifndef DISABLE_WARNING
+struct promise_void { // expected-note {{defined here}}
+#else
+struct promise_void {
+#endif
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+};
+
+template <typename... T>
+struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise_void; };
+
+#ifndef DISABLE_WARNING
+void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}}
+  co_return;   // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+  // expected-note at Inputs/std-coroutine-exp-namespace.h:8 {{'coroutine_traits' declared here}}
+}
+#else
+void test0() { // expected-no-diagnostics
+  co_return;
+}
+#endif

diff  --git a/clang/test/SemaCXX/coroutine-uninitialized-warning-crash-exp-namespace.cpp b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash-exp-namespace.cpp
new file mode 100644
index 0000000000000..3374084edda9d
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash-exp-namespace.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wall -Wextra -Wuninitialized  -fblocks
+#include "Inputs/std-coroutine-exp-namespace.h"
+
+using namespace std::experimental;
+
+struct A {
+  bool await_ready() { return true; }
+  int await_resume() { return 42; }
+  template <typename F>
+  void await_suspend(F) {}
+};
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object() { return {}; }
+    suspend_never initial_suspend() { return {}; }
+    suspend_never final_suspend() noexcept { return {}; }
+    A yield_value(int) { return {}; }
+    void return_void() {}
+    static void unhandled_exception() {}
+  };
+};
+
+coro_t f(int n) {
+  if (n == 0)
+    co_return;
+  co_yield 42;
+  int x = co_await A{};
+}
+
+template <class Await>
+coro_t g(int n) {
+  if (n == 0)
+    co_return;
+  co_yield 42;
+  int x = co_await Await{};
+}
+
+int main() {
+  f(0);
+  g<A>(0);
+}

diff  --git a/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp b/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp
new file mode 100644
index 0000000000000..14982143a420c
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine_handle-address-return-type-exp-namespace.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -verify %s -stdlib=libc++ -std=c++1z -fcoroutines-ts -fsyntax-only
+
+namespace std::experimental {
+template <class Promise = void>
+struct coroutine_handle;
+
+template <>
+struct coroutine_handle<void> {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept;
+  void *address() const;
+};
+
+template <class Promise>
+struct coroutine_handle : public coroutine_handle<> {
+};
+
+template <class... Args>
+struct void_t_imp {
+  using type = void;
+};
+template <class... Args>
+using void_t = typename void_t_imp<Args...>::type;
+
+template <class T, class = void>
+struct traits_sfinae_base {};
+
+template <class T>
+struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
+  using promise_type = typename T::promise_type;
+};
+
+template <class Ret, class... Args>
+struct coroutine_traits : public traits_sfinae_base<Ret> {};
+// expected-note at -1{{declared here}}
+} // namespace std::experimental
+
+struct suspend_never {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+struct task {
+  struct promise_type {
+    auto initial_suspend() { return suspend_never{}; }
+    auto final_suspend() noexcept { return suspend_never{}; }
+    auto get_return_object() { return task{}; }
+    static void unhandled_exception() {}
+    void return_void() {}
+  };
+};
+
+namespace std::experimental {
+template <>
+struct coroutine_handle<task::promise_type> : public coroutine_handle<> {
+  coroutine_handle<task::promise_type> *address() const; // expected-warning {{return type of 'coroutine_handle<>::address should be 'void*'}}
+};
+} // namespace std::experimental
+
+struct awaitable {
+  bool await_ready();
+
+  std::experimental::coroutine_handle<task::promise_type>
+  await_suspend(std::experimental::coroutine_handle<> handle);
+  void await_resume();
+} a;
+
+task f() {
+  co_await a; // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+}
+
+int main() {
+  f();
+  return 0;
+}

diff  --git a/clang/test/SemaCXX/coroutines-exp-namespace.cpp b/clang/test/SemaCXX/coroutines-exp-namespace.cpp
new file mode 100644
index 0000000000000..59af88f60f2f0
--- /dev/null
+++ b/clang/test/SemaCXX/coroutines-exp-namespace.cpp
@@ -0,0 +1,1443 @@
+// This file is the same as coroutines.cpp, except the components are defined in namespace std::experimental.
+// The intent of this test is to make sure the std::experimental implementation still works.
+// TODO: Remove this test once we drop support for <experimental/coroutine>.
+
+// RUN: %clang_cc1 -std=c++2b                 -fsyntax-only -verify=expected,cxx20_2b,cxx2b    %s -fcxx-exceptions -fexceptions -Wunused-result
+// RUN: %clang_cc1 -std=c++20                 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b %s -fcxx-exceptions -fexceptions -Wunused-result
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -fsyntax-only -verify=expected,cxx14_20          %s -fcxx-exceptions -fexceptions -Wunused-result
+
+void no_coroutine_traits_bad_arg_await() {
+  co_await a; // expected-error {{include <experimental/coroutine>}}
+  // expected-error at -1 {{use of undeclared identifier 'a'}}
+}
+
+void no_coroutine_traits_bad_arg_yield() {
+  co_yield a; // expected-error {{include <experimental/coroutine>}}
+  // expected-error at -1 {{use of undeclared identifier 'a'}}
+}
+
+void no_coroutine_traits_bad_arg_return() {
+  co_return a; // expected-error {{include <experimental/coroutine>}}
+  // expected-error at -1 {{use of undeclared identifier 'a'}}
+}
+
+void no_coroutine_traits() {
+  co_await 4; // expected-error {{std::coroutine_traits type was not found; include <coroutine> before defining a coroutine; include <experimental/coroutine> if your version of libcxx is less than 14.0}}
+}
+
+namespace std {
+namespace experimental {
+
+template <class... Args>
+struct void_t_imp {
+  using type = void;
+};
+template <class... Args>
+using void_t = typename void_t_imp<Args...>::type;
+
+template <class T, class = void>
+struct traits_sfinae_base {};
+
+template <class T>
+struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
+  using promise_type = typename T::promise_type;
+};
+
+template <class Ret, class... Args>
+struct coroutine_traits : public traits_sfinae_base<Ret> {};
+// expected-note at -1{{declared here}}
+} // namespace experimental
+} // namespace std
+
+template <typename Promise> struct coro {};
+template <typename Promise, typename... Ps>
+struct std::experimental::coroutine_traits<coro<Promise>, Ps...> {
+  using promise_type = Promise;
+};
+
+struct awaitable {
+  bool await_ready() noexcept;
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
+} a;
+
+struct suspend_always {
+  bool await_ready() noexcept { return false; }
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
+};
+
+struct suspend_never {
+  bool await_ready() noexcept { return true; }
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
+};
+
+struct auto_await_suspend {
+  bool await_ready();
+  template <typename F> auto await_suspend(F) {}
+  void await_resume();
+};
+
+struct DummyVoidTag {};
+DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}}
+  co_await a;                      // expected-warning {{support for 'std::experimental::coroutine_traits' will be removed}}
+}
+
+template <typename... T>
+struct std::experimental::coroutine_traits<int, T...> {};
+
+int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}}
+  co_await a;
+}
+
+int no_promise_type_multiple_awaits(int) { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int, int>' has no member named 'promise_type'}}
+  co_await a;
+  co_await a;
+}
+
+template <>
+struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; };
+double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
+  co_await a;
+}
+
+template <>
+struct std::experimental::coroutine_traits<double, int> {
+  struct promise_type {};
+};
+double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}}
+  co_yield 0;                    // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}}
+}
+
+struct promise; // expected-note {{forward declaration}}
+struct promise_void;
+struct void_tag {};
+template <typename... T>
+struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; };
+template <typename... T>
+struct std::experimental::coroutine_traits<void, void_tag, T...> { using promise_type = promise_void; };
+
+// FIXME: This diagnostic is terrible.
+void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<void>::promise_type' (aka 'promise') is an incomplete type}}
+  co_await a;
+}
+
+struct yielded_thing {
+  const char *p;
+  short a, b;
+};
+
+struct not_awaitable {};
+
+struct promise {
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  awaitable yield_value(int);           // expected-note 2{{candidate}}
+  awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
+  not_awaitable yield_value(void());    // expected-note 2{{candidate}}
+  void return_value(int);               // expected-note 2{{here}}
+  void unhandled_exception();
+};
+
+struct promise_void {
+  void get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+void no_coroutine_handle() { // expected-error {{std::coroutine_handle type was not found; include <coroutine> before defining a coroutine; include <experimental/coroutine> if your version of libcxx is less than 14.0}}
+  //expected-note at -1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+  co_return 5; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+namespace std {
+namespace experimental {
+template <class PromiseType = void>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) noexcept;
+};
+template <>
+struct coroutine_handle<void> {
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
+};
+} // namespace experimental
+} // namespace std
+
+void yield() {
+  co_yield 0;
+  co_yield {"foo", 1, 2};
+  co_yield {1e100};                    // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{implicit conversion}} expected-warning {{braces around scalar}}
+  co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}}
+  co_yield {"foo"};
+  co_yield "foo"; // expected-error {{no matching}}
+  co_yield 1.0;
+  co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+}
+
+void check_auto_await_suspend() {
+  co_await auto_await_suspend{}; // Should compile successfully.
+}
+
+void coreturn(int n) {
+  co_await a;
+  if (n == 0)
+    co_return 3;
+  if (n == 1)
+    co_return {4}; // expected-warning {{braces around scalar initializer}}
+  if (n == 2)
+    co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char[4]'}}
+  co_return 42;
+}
+
+template <class T>
+void co_await_non_dependent_arg(T) {
+  co_await a;
+}
+template void co_await_non_dependent_arg(int);
+
+void mixed_yield() {
+  co_yield 0; // expected-note {{use of 'co_yield'}}
+  return;     // expected-error {{not allowed in coroutine}}
+}
+
+void mixed_yield_invalid() {
+  co_yield blah; // expected-error {{use of undeclared identifier}}
+  // expected-note at -1 {{function is a coroutine due to use of 'co_yield'}}
+  return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template(T) {
+  co_yield blah; // expected-error {{use of undeclared identifier}}
+  // expected-note at -1 {{function is a coroutine due to use of 'co_yield'}}
+  return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template2(T) {
+  co_yield 42;
+  // expected-note at -1 {{function is a coroutine due to use of 'co_yield'}}
+  return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_yield_template3(T v) {
+  co_yield blah(v);
+  // expected-note at -1 {{function is a coroutine due to use of 'co_yield'}}
+  return; // expected-error {{return statement not allowed in coroutine}}
+}
+
+void mixed_await() {
+  co_await a; // expected-note {{use of 'co_await'}}
+  return;     // expected-error {{not allowed in coroutine}}
+}
+
+void mixed_await_invalid() {
+  co_await 42; // expected-error {{'int' is not a structure or union}}
+  // expected-note at -1 {{function is a coroutine due to use of 'co_await'}}
+  return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_await_template(T) {
+  co_await 42;
+  // expected-note at -1 {{function is a coroutine due to use of 'co_await'}}
+  return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_await_template2(T v) {
+  co_await v; // expected-error {{'long' is not a structure or union}}
+  // expected-note at -1 {{function is a coroutine due to use of 'co_await'}}
+  return; // expected-error {{not allowed in coroutine}}
+}
+template void mixed_await_template2(long); // expected-note {{requested here}}
+
+void only_coreturn(void_tag) {
+  co_return; // OK
+}
+
+void mixed_coreturn(void_tag, bool b) {
+  if (b)
+    co_return; // expected-note {{use of 'co_return'}}
+  else
+    return; // expected-error {{not allowed in coroutine}}
+}
+
+void mixed_coreturn_invalid(bool b) {
+  if (b)
+    co_return; // expected-note {{use of 'co_return'}}
+  // expected-error at -1 {{no member named 'return_void' in 'promise'}}
+  else
+    return; // expected-error {{not allowed in coroutine}}
+}
+
+template <class T>
+void mixed_coreturn_template(void_tag, bool b, T v) {
+  if (b)
+    co_return v; // expected-note {{use of 'co_return'}}
+  // expected-error at -1 {{no member named 'return_value' in 'promise_void'}}
+  else
+    return; // expected-error {{not allowed in coroutine}}
+}
+template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{requested here}}
+
+template <class T>
+void mixed_coreturn_template2(bool b, T) {
+  if (b)
+    co_return v; // expected-note {{use of 'co_return'}}
+  // expected-error at -1 {{use of undeclared identifier 'v'}}
+  else
+    return; // expected-error {{not allowed in coroutine}}
+}
+
+struct CtorDtor {
+  CtorDtor() {
+    co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
+  }
+  CtorDtor(awaitable a) {
+    // The spec doesn't say this is ill-formed, but it must be.
+    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}}
+  }
+  void operator=(CtorDtor &) {
+    co_yield 0; // OK.
+  }
+  void operator=(CtorDtor const &) {
+    co_yield 0; // OK.
+  }
+  void operator=(CtorDtor &&) {
+    co_await a; // OK.
+  }
+  void operator=(CtorDtor const &&) {
+    co_await a; // OK.
+  }
+  void operator=(int) {
+    co_await a; // OK. Not a special member
+  }
+};
+
+namespace std {
+class type_info;
+}
+
+void unevaluated() {
+  decltype(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
+}
+
+void unevaluated2() {
+  sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
+}
+
+void unevaluated3() {
+  typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
+}
+
+void unevaluated4() {
+  decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
+}
+
+void unevaluated5() {
+  sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
+}
+
+void unevaluated6() {
+  typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
+}
+
+// [expr.await]p2: "An await-expression shall not appear in a default argument."
+// FIXME: A better diagnostic would explicitly state that default arguments are
+// not allowed. A user may not understand that this is "outside a function."
+void default_argument(int arg = co_await 0) {} // expected-error {{'co_await' cannot be used outside a function}}
+
+void await_in_catch_coroutine() {
+  try {
+  } catch (...) {                   // FIXME: Emit a note diagnostic pointing out the try handler on this line.
+    []() -> void { co_await a; }(); // OK
+    co_await a;                     // expected-error {{'co_await' cannot be used in the handler of a try block}}
+  }
+}
+
+void await_nested_in_catch_coroutine() {
+  try {
+  } catch (...) { // FIXME: Emit a note diagnostic pointing out the try handler on this line.
+    try {
+      co_await a;                     // expected-error {{'co_await' cannot be used in the handler of a try block}}
+      []() -> void { co_await a; }(); // OK
+    } catch (...) {
+      co_return 123;
+    }
+  }
+}
+
+void await_in_lambda_in_catch_coroutine() {
+  try {
+  } catch (...) {
+    []() -> void { co_await a; }(); // OK
+  }
+}
+
+void yield_in_catch_coroutine() {
+  try {
+  } catch (...) {
+    co_yield 1; // expected-error {{'co_yield' cannot be used in the handler of a try block}}
+  }
+}
+
+void return_in_catch_coroutine() {
+  try {
+  } catch (...) {
+    co_return 123; // OK
+  }
+}
+
+constexpr auto constexpr_deduced_return_coroutine() {
+  co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
+  // expected-error at -1 {{'co_yield' cannot be used in a function with a deduced return type}}
+}
+
+void varargs_coroutine(const char *, ...) {
+  co_await a; // expected-error {{'co_await' cannot be used in a varargs function}}
+}
+
+auto deduced_return_coroutine() {
+  co_await a; // expected-error {{'co_await' cannot be used in a function with a deduced return type}}
+}
+
+struct outer {};
+struct await_arg_1 {};
+struct await_arg_2 {};
+
+namespace adl_ns {
+struct coawait_arg_type {};
+awaitable operator co_await(coawait_arg_type) noexcept;
+} // namespace adl_ns
+
+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);
+
+struct transform_awaitable {};
+struct transformed {};
+
+struct transform_promise {
+  typedef transform_awaitable await_arg;
+  coro<transform_promise> get_return_object();
+  transformed initial_suspend();
+  ::adl_ns::coawait_arg_type final_suspend() noexcept;
+  transformed await_transform(transform_awaitable);
+  void unhandled_exception();
+  void return_void();
+};
+template <class AwaitArg>
+struct basic_promise {
+  typedef AwaitArg await_arg;
+  coro<basic_promise> get_return_object();
+  awaitable initial_suspend();
+  awaitable final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+};
+
+awaitable operator co_await(await_arg_1);
+
+template <typename T, typename U>
+coro<T> await_template_3(U t) {
+  co_await t;
+}
+
+template coro<basic_promise<await_arg_1>> await_template_3<basic_promise<await_arg_1>>(await_arg_1);
+
+template <class T, int I = 0>
+struct dependent_member {
+  coro<T> mem_fn() const {
+    co_await typename T::await_arg{}; // expected-error {{call to function 'operator co_await'}}}
+  }
+  template <class U>
+  coro<T> dep_mem_fn(U t) {
+    co_await t;
+  }
+};
+
+template <>
+struct dependent_member<long> {
+  // FIXME this diagnostic is terrible
+  coro<transform_promise> mem_fn() const { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}}
+    // expected-note at -1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+    // expected-note at +1 {{function is a coroutine due to use of 'co_await' here}}
+    co_await transform_awaitable{};
+    // expected-error at -1 {{no member named 'await_ready'}}
+  }
+  template <class R, class U>
+  coro<R> dep_mem_fn(U u) { co_await u; }
+};
+
+awaitable operator co_await(await_arg_2); // expected-note {{'operator co_await' should be declared prior to the call site}}
+
+template struct dependent_member<basic_promise<await_arg_1>, 0>;
+template struct dependent_member<basic_promise<await_arg_2>, 0>; // expected-note {{in instantiation}}
+
+template <>
+coro<transform_promise>
+// FIXME this diagnostic is terrible
+dependent_member<long>::dep_mem_fn<transform_promise>(int) { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}}
+  //expected-note at -1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+  //expected-note at +1 {{function is a coroutine due to use of 'co_await' here}}
+  co_await transform_awaitable{};
+  // expected-error at -1 {{no member named 'await_ready'}}
+}
+
+void operator co_await(transform_awaitable) = delete;
+awaitable operator co_await(transformed);
+
+template coro<transform_promise>
+    dependent_member<long>::dep_mem_fn<transform_promise>(transform_awaitable);
+
+template <>
+coro<transform_promise> dependent_member<long>::dep_mem_fn<transform_promise>(long) {
+  co_await transform_awaitable{};
+}
+
+template <>
+struct dependent_member<int> {
+  coro<transform_promise> mem_fn() const {
+    co_await transform_awaitable{};
+  }
+};
+
+template coro<transform_promise> await_template_3<transform_promise>(transform_awaitable);
+template struct dependent_member<transform_promise>;
+template coro<transform_promise> dependent_member<transform_promise>::dep_mem_fn(transform_awaitable);
+} // namespace dependent_operator_co_await_lookup
+
+struct yield_fn_tag {};
+template <>
+struct std::experimental::coroutine_traits<void, yield_fn_tag> {
+  struct promise_type {
+    // FIXME: add an await_transform overload for functions
+    awaitable yield_value(int());
+    void return_value(int());
+
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void get_return_object();
+    void unhandled_exception();
+  };
+};
+
+namespace placeholder {
+awaitable f(), f(int); // expected-note 4{{possible target}}
+int g(), g(int);       // expected-note 2{{candidate}}
+void x() {
+  co_await f; // expected-error {{reference to overloaded function}}
+}
+void y() {
+  co_yield g; // expected-error {{no matching member function for call to 'yield_value'}}
+}
+void z() {
+  co_await a;
+  co_return g; // expected-error {{address of overloaded function 'g' does not match required type 'int'}}
+}
+
+void x(yield_fn_tag) {
+  co_await f; // expected-error {{reference to overloaded function}}
+}
+void y(yield_fn_tag) {
+  co_yield g;
+}
+void z(yield_fn_tag) {
+  co_await a;
+  co_return g;
+}
+} // namespace placeholder
+
+struct bad_promise_1 {
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+};
+coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}}
+  co_await a;
+}
+
+struct bad_promise_2 {
+  coro<bad_promise_2> get_return_object();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+};
+// FIXME: This shouldn't happen twice
+coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}}
+  co_await a;
+}
+
+struct bad_promise_3 {
+  coro<bad_promise_3> get_return_object();
+  suspend_always initial_suspend();
+  void unhandled_exception();
+  void return_void();
+};
+coro<bad_promise_3> missing_final_suspend() noexcept { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
+  co_await a;
+}
+
+struct bad_promise_4 {
+  coro<bad_promise_4> get_return_object();
+  not_awaitable initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+};
+// FIXME: This diagnostic is terrible.
+coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+  // expected-note at -1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+  co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
+}
+
+struct bad_promise_5 {
+  coro<bad_promise_5> get_return_object();
+  suspend_always initial_suspend();
+  not_awaitable final_suspend() noexcept;
+  void return_void();
+};
+// FIXME: This diagnostic is terrible.
+coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
+  // expected-note at -1 {{call to 'final_suspend' implicitly required by the final suspend point}}
+  co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
+}
+
+struct bad_promise_6 {
+  coro<bad_promise_6> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();           // expected-note 2 {{member 'return_void' first declared here}}
+  void return_value(int) const; // expected-note 2 {{member 'return_value' first declared here}}
+  void return_value(int);
+};
+coro<bad_promise_6> bad_implicit_return() { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}}
+  co_await a;
+}
+
+template <class T>
+coro<T> bad_implicit_return_dependent(T) { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}}
+  co_await a;
+}
+template coro<bad_promise_6> bad_implicit_return_dependent(bad_promise_6); // expected-note {{in instantiation}}
+
+struct bad_promise_7 { // expected-note 2 {{defined here}}
+  coro<bad_promise_7> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+};
+coro<bad_promise_7> no_unhandled_exception() { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}}
+  co_await a;
+}
+
+template <class T>
+coro<T> no_unhandled_exception_dependent(T) { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}}
+  co_await a;
+}
+template coro<bad_promise_7> no_unhandled_exception_dependent(bad_promise_7); // expected-note {{in instantiation}}
+
+struct bad_promise_base {
+private:
+  void return_void(); // expected-note 2 {{declared private here}}
+};
+struct bad_promise_8 : bad_promise_base {
+  coro<bad_promise_8> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception() __attribute__((unavailable)); // expected-note 2 {{marked unavailable here}}
+  void unhandled_exception() const;
+  void unhandled_exception(void *) const;
+};
+coro<bad_promise_8> calls_unhandled_exception() {
+  // expected-error at -1 {{'unhandled_exception' is unavailable}}
+  // expected-error at -2 {{'return_void' is a private member}}
+  co_await a;
+}
+
+template <class T>
+coro<T> calls_unhandled_exception_dependent(T) {
+  // expected-error at -1 {{'unhandled_exception' is unavailable}}
+  // expected-error at -2 {{'return_void' is a private member}}
+  co_await a;
+}
+template coro<bad_promise_8> calls_unhandled_exception_dependent(bad_promise_8); // expected-note {{in instantiation}}
+
+struct bad_promise_9 {
+  coro<bad_promise_9> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void await_transform(void *);
+  awaitable await_transform(int) __attribute__((unavailable)); // expected-note {{explicitly marked unavailable}}
+  void return_void();
+  void unhandled_exception();
+};
+coro<bad_promise_9> calls_await_transform() {
+  co_await 42; // expected-error {{'await_transform' is unavailable}}
+}
+
+struct bad_promise_10 {
+  coro<bad_promise_10> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  int await_transform;
+  void return_void();
+  void unhandled_exception();
+};
+coro<bad_promise_10> bad_coawait() {
+  // FIXME this diagnostic is terrible
+  co_await 42; // expected-error {{called object type 'int' is not a function or function pointer}}
+  // expected-note at -1 {{call to 'await_transform' implicitly required by 'co_await' here}}
+}
+
+struct call_operator {
+  template <class... Args>
+  awaitable operator()(Args...) const { return a; }
+};
+void ret_void();
+struct good_promise_1 {
+  coro<good_promise_1> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  static const call_operator await_transform;
+  using Fn = void (*)();
+  Fn return_void = ret_void;
+};
+const call_operator good_promise_1::await_transform;
+coro<good_promise_1> ok_static_coawait() {
+  // FIXME this diagnostic is terrible
+  co_await 42;
+}
+
+template <typename T> void ok_generic_lambda_coawait_PR41909() {
+  [](auto &arg) -> coro<good_promise_1> { // expected-warning {{expression result unused}}
+    co_await 12;
+  };
+  [](auto &arg) -> coro<good_promise_1> {
+    co_await 24;
+  }("argument");
+  [](auto &arg) -> coro<good_promise_1> { // expected-warning {{expression result unused}}
+    []() -> coro<good_promise_1> {
+      co_await 36;
+    };
+    co_await 48;
+  };
+}
+template void ok_generic_lambda_coawait_PR41909<int>(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909<int>' requested here}}
+
+template <> struct std::experimental::coroutine_traits<int, int, const char **> { using promise_type = promise; };
+
+int main(int, const char **) {
+  co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}}
+}
+
+struct good_promise_2 {
+  float get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+template <> struct std::experimental::coroutine_handle<good_promise_2> {};
+
+template <> struct std::experimental::coroutine_traits<float> { using promise_type = good_promise_2; };
+
+float badly_specialized_coro_handle() { // expected-error {{std::coroutine_handle must have a member named 'from_address'}}
+  //expected-note at -1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+namespace std {
+struct nothrow_t {};
+constexpr nothrow_t nothrow = {};
+} // namespace std
+
+using SizeT = decltype(sizeof(int));
+
+void *operator new(SizeT __sz, const std::nothrow_t &) noexcept;
+void operator delete(void *__p, const std::nothrow_t &)noexcept;
+
+struct promise_on_alloc_failure_tag {};
+
+template <>
+struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
+  struct promise_type {
+    int get_return_object() {}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    int get_return_object_on_allocation_failure(); // expected-error{{'promise_type': 'get_return_object_on_allocation_failure()' must be a static member function}}
+    void unhandled_exception();
+  };
+};
+
+extern "C" int f(promise_on_alloc_failure_tag) {
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct bad_promise_11 {
+  coro<bad_promise_11> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+
+private:
+  static coro<bad_promise_11> get_return_object_on_allocation_failure(); // expected-note 2 {{declared private here}}
+};
+coro<bad_promise_11> private_alloc_failure_handler() {
+  // expected-error at -1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}}
+  co_return; // FIXME: Add a "declared coroutine here" note.
+}
+
+template <class T>
+coro<T> dependent_private_alloc_failure_handler(T) {
+  // expected-error at -1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}}
+  co_return; // FIXME: Add a "declared coroutine here" note.
+}
+template coro<bad_promise_11> dependent_private_alloc_failure_handler(bad_promise_11);
+// expected-note at -1 {{requested here}}
+
+struct bad_promise_12 {
+  coro<bad_promise_12> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+  static coro<bad_promise_12> get_return_object_on_allocation_failure();
+
+  static void *operator new(SizeT);
+  // expected-error at -1 2 {{'operator new' is required to have a non-throwing noexcept specification when the promise type declares 'get_return_object_on_allocation_failure()'}}
+};
+coro<bad_promise_12> throwing_in_class_new() { // expected-note {{call to 'operator new' implicitly required by coroutine function here}}
+  co_return;
+}
+
+template <class T>
+coro<T> dependent_throwing_in_class_new(T) { // expected-note {{call to 'operator new' implicitly required by coroutine function here}}
+  co_return;
+}
+template coro<bad_promise_12> dependent_throwing_in_class_new(bad_promise_12); // expected-note {{requested here}}
+
+struct good_promise_13 {
+  coro<good_promise_13> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+  void return_void();
+  static coro<good_promise_13> get_return_object_on_allocation_failure();
+};
+coro<good_promise_13> uses_nothrow_new() {
+  co_return;
+}
+
+template <class T>
+coro<T> dependent_uses_nothrow_new(T) {
+  co_return;
+}
+template coro<good_promise_13> dependent_uses_nothrow_new(good_promise_13);
+
+struct good_promise_custom_new_operator {
+  coro<good_promise_custom_new_operator> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+  void *operator new(SizeT, double, float, int);
+};
+
+coro<good_promise_custom_new_operator>
+good_coroutine_calls_custom_new_operator(double, float, int) {
+  co_return;
+}
+
+struct coroutine_nonstatic_member_struct;
+
+struct good_promise_nonstatic_member_custom_new_operator {
+  coro<good_promise_nonstatic_member_custom_new_operator> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+  void *operator new(SizeT, coroutine_nonstatic_member_struct &, double);
+};
+
+struct good_promise_noexcept_custom_new_operator {
+  static coro<good_promise_noexcept_custom_new_operator> get_return_object_on_allocation_failure();
+  coro<good_promise_noexcept_custom_new_operator> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+  void *operator new(SizeT, double, float, int) noexcept;
+};
+
+coro<good_promise_noexcept_custom_new_operator>
+good_coroutine_calls_noexcept_custom_new_operator(double, float, int) {
+  co_return;
+}
+
+struct mismatch_gro_type_tag1 {};
+template <>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> {
+  struct promise_type {
+    void get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception();
+  };
+};
+
+extern "C" int f(mismatch_gro_type_tag1) {
+  // expected-error at -1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}}
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct mismatch_gro_type_tag2 {};
+template <>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag2> {
+  struct promise_type {
+    void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception();
+  };
+};
+
+extern "C" int f(mismatch_gro_type_tag2) {
+  // cxx2b-error at -1 {{cannot initialize return object of type 'int' with an rvalue of type 'void *'}}
+  // cxx14_20-error at -2 {{cannot initialize return object of type 'int' with an rvalue of type 'void *'}}
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct mismatch_gro_type_tag3 {};
+template <>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag3> {
+  struct promise_type {
+    int get_return_object() {}
+    static void get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared here}}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception();
+  };
+};
+
+extern "C" int f(mismatch_gro_type_tag3) {
+  // expected-error at -1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}}
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct mismatch_gro_type_tag4 {};
+template <>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag4> {
+  struct promise_type {
+    int get_return_object() {}
+    static char *get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared}}
+    suspend_always initial_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception();
+  };
+};
+
+extern "C" int f(mismatch_gro_type_tag4) {
+  // expected-error at -1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}}
+  co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct bad_await_suspend_return {
+  bool await_ready();
+  // expected-error at +1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}}
+  char await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+struct bad_await_ready_return {
+  // expected-note at +1 {{return type of 'await_ready' is required to be contextually convertible to 'bool'}}
+  void await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+struct await_ready_explicit_bool {
+  struct BoolT {
+    explicit operator bool() const;
+  };
+  BoolT await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+template <class SuspendTy>
+struct await_suspend_type_test {
+  bool await_ready();
+  // expected-error at +2 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &')}}
+  // expected-error at +1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &&')}}
+  SuspendTy await_suspend(std::experimental::coroutine_handle<>);
+  // cxx20_2b-warning at -1 {{volatile-qualified return type 'const volatile bool' is deprecated}}
+  void await_resume();
+};
+void test_bad_suspend() {
+  {
+    // FIXME: The actual error emitted here is terrible, and no number of notes can save it.
+    bad_await_ready_return a;
+    // expected-error at +1 {{value of type 'void' is not contextually convertible to 'bool'}}
+    co_await a; // expected-note {{call to 'await_ready' implicitly required by coroutine function here}}
+  }
+  {
+    bad_await_suspend_return b;
+    co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+  }
+  {
+    await_ready_explicit_bool c;
+    co_await c; // OK
+  }
+  {
+    await_suspend_type_test<bool &&> a;
+    await_suspend_type_test<bool &> b;
+    await_suspend_type_test<const void> c;
+    await_suspend_type_test<const volatile bool> d; // cxx20_2b-note {{in instantiation of template class}}
+    co_await a;                                     // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+    co_await b;                                     // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+    co_await c;                                     // OK
+    co_await d;                                     // OK
+  }
+}
+
+template <int ID = 0>
+struct NoCopy {
+  NoCopy(NoCopy const &) = delete; // expected-note 2 {{deleted here}}
+};
+template <class T, class U>
+void test_dependent_param(T t, U) {
+  // expected-error at -1 {{call to deleted constructor of 'NoCopy<>'}}
+  // expected-error at -2 {{call to deleted constructor of 'NoCopy<1>'}}
+  ((void)t);
+  co_return 42;
+}
+template void test_dependent_param(NoCopy<0>, NoCopy<1>); // expected-note {{requested here}}
+
+namespace CoroHandleMemberFunctionTest {
+struct CoroMemberTag {};
+struct BadCoroMemberTag {};
+
+template <class T, class U>
+constexpr bool IsSameV = false;
+template <class T>
+constexpr bool IsSameV<T, T> = true;
+
+template <class T>
+struct TypeTest {
+  template <class U>
+  static constexpr bool IsSame = IsSameV<T, U>;
+
+  template <class... Args>
+  static constexpr bool MatchesArgs = IsSameV<T,
+                                              std::experimental::coroutine_traits<CoroMemberTag, Args...>>;
+};
+
+template <class T>
+struct AwaitReturnsType {
+  bool await_ready() const;
+  void await_suspend(...) const;
+  T await_resume() const;
+};
+
+template <class... CoroTraitsArgs>
+struct CoroMemberPromise {
+  using TraitsT = std::experimental::coroutine_traits<CoroTraitsArgs...>;
+  using TypeTestT = TypeTest<TraitsT>;
+  using AwaitTestT = AwaitReturnsType<TypeTestT>;
+
+  CoroMemberTag get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+
+  AwaitTestT yield_value(int);
+
+  void return_void();
+  void unhandled_exception();
+};
+
+} // namespace CoroHandleMemberFunctionTest
+
+template <class... Args>
+struct ::std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> {
+  using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise<CoroHandleMemberFunctionTest::CoroMemberTag, Args...>;
+};
+
+namespace CoroHandleMemberFunctionTest {
+struct TestType {
+
+  CoroMemberTag test_qual() {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType &>, "");
+    static_assert(!TC.MatchesArgs<TestType>, "");
+    static_assert(!TC.MatchesArgs<TestType *>, "");
+  }
+
+  CoroMemberTag test_asserts(int *) const {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static assertion failed}}
+    static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static assertion failed}}
+    static_assert(TC.MatchesArgs<const TestType &, int *>, "");
+  }
+
+  CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const {
+    // cxx20_2b-warning at -1 {{volatile-qualified parameter type}}
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<const TestType &, int *, const float &&, volatile void *volatile>, "");
+  }
+
+  CoroMemberTag test_qual() const volatile {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<const volatile TestType &>, "");
+  }
+
+  CoroMemberTag test_ref_qual() & {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType &>, "");
+  }
+  CoroMemberTag test_ref_qual() const & {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType const &>, "");
+  }
+  CoroMemberTag test_ref_qual() && {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType &&>, "");
+  }
+  CoroMemberTag test_ref_qual(const char *&) const volatile && {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType const volatile &&, const char *&>, "");
+  }
+
+  CoroMemberTag test_args(int) {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType &, int>, "");
+  }
+  CoroMemberTag test_args(int, long &, void *) const {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<TestType const &, int, long &, void *>, "");
+  }
+
+  template <class... Args>
+  CoroMemberTag test_member_template(Args...) const && {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<TestType const &&, Args...>, "");
+  }
+
+  static CoroMemberTag test_static() {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<>, "");
+    static_assert(!TC.MatchesArgs<TestType>, "");
+    static_assert(!TC.MatchesArgs<TestType &>, "");
+    static_assert(!TC.MatchesArgs<TestType *>, "");
+  }
+
+  static CoroMemberTag test_static(volatile void *const, char &&) {
+    auto TC = co_yield 0;
+    static_assert(TC.MatchesArgs<volatile void *const, char &&>, "");
+  }
+
+  template <class Dummy>
+  static CoroMemberTag test_static_template(const char *volatile &, unsigned) {
+    auto TC = co_yield 0;
+    using TCT = decltype(TC);
+    static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, "");
+    static_assert(!TCT::MatchesArgs<TestType &, const char *volatile &, unsigned>, "");
+  }
+
+  BadCoroMemberTag test_diagnostics() {
+    // expected-error at -1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}}
+    co_return;
+  }
+  BadCoroMemberTag test_diagnostics(int) const && {
+    // expected-error at -1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}}
+    co_return;
+  }
+
+  static BadCoroMemberTag test_static_diagnostics(long *) {
+    // expected-error at -1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}}
+    co_return;
+  }
+};
+
+template CoroMemberTag TestType::test_member_template(long, const char *) const &&;
+template CoroMemberTag TestType::test_static_template<void>(const char *volatile &, unsigned);
+
+template <class... Args>
+struct DepTestType {
+
+  CoroMemberTag test_asserts(int *) const {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<const DepTestType &>, ""); // expected-error {{static assertion failed}}
+    static_assert(TC.template MatchesArgs<>, "");                    // expected-error {{static assertion failed}}
+    static_assert(TC.template MatchesArgs<const DepTestType &, int *>, "");
+  }
+
+  CoroMemberTag test_qual() {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType &>, "");
+    static_assert(!TC.template MatchesArgs<DepTestType>, "");
+    static_assert(!TC.template MatchesArgs<DepTestType *>, "");
+  }
+
+  CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const {
+    // cxx20_2b-warning at -1 {{volatile-qualified parameter type}}
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<const DepTestType &, int *, const float &&, volatile void *volatile>, "");
+  }
+
+  CoroMemberTag test_qual() const volatile {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<const volatile DepTestType &>, "");
+  }
+
+  CoroMemberTag test_ref_qual() & {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType &>, "");
+  }
+  CoroMemberTag test_ref_qual() const & {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType const &>, "");
+  }
+  CoroMemberTag test_ref_qual() && {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType &&>, "");
+  }
+  CoroMemberTag test_ref_qual(const char *&) const volatile && {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType const volatile &&, const char *&>, "");
+  }
+
+  CoroMemberTag test_args(int) {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType &, int>, "");
+  }
+  CoroMemberTag test_args(int, long &, void *) const {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType const &, int, long &, void *>, "");
+  }
+
+  template <class... UArgs>
+  CoroMemberTag test_member_template(UArgs...) const && {
+    auto TC = co_yield 0;
+    static_assert(TC.template MatchesArgs<DepTestType const &&, UArgs...>, "");
+  }
+
+  static CoroMemberTag test_static() {
+    auto TC = co_yield 0;
+    using TCT = decltype(TC);
+    static_assert(TCT::MatchesArgs<>, "");
+    static_assert(!TCT::MatchesArgs<DepTestType>, "");
+    static_assert(!TCT::MatchesArgs<DepTestType &>, "");
+    static_assert(!TCT::MatchesArgs<DepTestType *>, "");
+
+    // Ensure diagnostics are actually being generated here
+    static_assert(TCT::MatchesArgs<int>, ""); // expected-error {{static assertion failed}}
+  }
+
+  static CoroMemberTag test_static(volatile void *const, char &&) {
+    auto TC = co_yield 0;
+    using TCT = decltype(TC);
+    static_assert(TCT::MatchesArgs<volatile void *const, char &&>, "");
+  }
+
+  template <class Dummy>
+  static CoroMemberTag test_static_template(const char *volatile &, unsigned) {
+    auto TC = co_yield 0;
+    using TCT = decltype(TC);
+    static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, "");
+    static_assert(!TCT::MatchesArgs<DepTestType &, const char *volatile &, unsigned>, "");
+  }
+};
+
+template struct DepTestType<int>; // expected-note {{requested here}}
+template CoroMemberTag DepTestType<int>::test_member_template(long, const char *) const &&;
+
+template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned);
+
+struct bad_promise_deleted_constructor {
+  // expected-note at +1 {{'bad_promise_deleted_constructor' has been explicitly marked deleted here}}
+  bad_promise_deleted_constructor() = delete;
+  coro<bad_promise_deleted_constructor> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+coro<bad_promise_deleted_constructor>
+bad_coroutine_calls_deleted_promise_constructor() {
+  // expected-error at -1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_deleted_constructor>>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}}
+  co_return;
+}
+
+// Test that, when the promise type has a constructor whose signature matches
+// that of the coroutine function, that constructor is used. If no matching
+// constructor exists, the default constructor is used as a fallback. If no
+// matching constructors exist at all, an error is emitted. This is an
+// experimental feature that will be proposed for the Coroutines TS.
+
+struct good_promise_default_constructor {
+  good_promise_default_constructor(double, float, int);
+  good_promise_default_constructor() = default;
+  coro<good_promise_default_constructor> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+coro<good_promise_default_constructor>
+good_coroutine_calls_default_constructor() {
+  co_return;
+}
+
+struct some_class;
+
+struct good_promise_custom_constructor {
+  good_promise_custom_constructor(some_class &, float, int);
+  good_promise_custom_constructor(double, float, int);
+  good_promise_custom_constructor() = delete;
+  coro<good_promise_custom_constructor> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+coro<good_promise_custom_constructor>
+good_coroutine_calls_custom_constructor(double, float, int) {
+  co_return;
+}
+
+struct some_class {
+  coro<good_promise_custom_constructor>
+  good_coroutine_calls_custom_constructor(float, int) {
+    co_return;
+  }
+  coro<good_promise_custom_constructor> static good_coroutine_calls_custom_constructor(double, float, int) {
+    co_return;
+  }
+};
+
+struct bad_promise_no_matching_constructor {
+  bad_promise_no_matching_constructor(int, int, int);
+  // expected-note at +1 2 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}}
+  bad_promise_no_matching_constructor() = delete;
+  coro<bad_promise_no_matching_constructor> get_return_object();
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void return_void();
+  void unhandled_exception();
+};
+
+coro<bad_promise_no_matching_constructor>
+bad_coroutine_calls_with_no_matching_constructor(int, int) {
+  // expected-error at -1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor>, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}}
+  co_return;
+}
+
+struct some_class2 {
+  coro<bad_promise_no_matching_constructor>
+  bad_coroutine_calls_with_no_matching_constructor(int, int, int) {
+    // expected-error at -1 {{call to deleted constructor}}
+    co_return;
+  }
+};
+
+} // namespace CoroHandleMemberFunctionTest
+
+class awaitable_no_unused_warn {
+public:
+  using handle_type = std::experimental::coroutine_handle<>;
+  constexpr bool await_ready() noexcept { return false; }
+  void await_suspend(handle_type) noexcept {}
+  int await_resume() noexcept { return 1; }
+};
+
+class awaitable_unused_warn {
+public:
+  using handle_type = std::experimental::coroutine_handle<>;
+  constexpr bool await_ready() noexcept { return false; }
+  void await_suspend(handle_type) noexcept {}
+  [[nodiscard]] int await_resume() noexcept { return 1; }
+};
+
+template <class Await>
+struct check_warning_promise {
+  coro<check_warning_promise> get_return_object();
+  Await initial_suspend();
+  Await final_suspend() noexcept;
+  Await yield_value(int);
+  void return_void();
+  void unhandled_exception();
+};
+
+coro<check_warning_promise<awaitable_no_unused_warn>>
+test_no_unused_warning() {
+  co_await awaitable_no_unused_warn();
+  co_yield 42;
+}
+
+coro<check_warning_promise<awaitable_unused_warn>>
+test_unused_warning() {
+  co_await awaitable_unused_warn(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  co_yield 42;                      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+struct missing_await_ready {
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+struct missing_await_suspend {
+  bool await_ready();
+  void await_resume();
+};
+struct missing_await_resume {
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+};
+
+void test_missing_awaitable_members() {
+  co_await missing_await_ready{};   // expected-error {{no member named 'await_ready' in 'missing_await_ready'}}
+  co_await missing_await_suspend{}; // expected-error {{no member named 'await_suspend' in 'missing_await_suspend'}}
+  co_await missing_await_resume{};  // expected-error {{no member named 'await_resume' in 'missing_await_resume'}}
+}


        


More information about the cfe-commits mailing list