Author: Xun Li
Date: 2020-06-22T15:01:42-07:00
New Revision: 516803dc8685ebcc5bce38b05391958ffee22643

URL: 
https://github.com/llvm/llvm-project/commit/516803dc8685ebcc5bce38b05391958ffee22643
DIFF: 
https://github.com/llvm/llvm-project/commit/516803dc8685ebcc5bce38b05391958ffee22643.diff

LOG: [Coroutines] Ensure co_await promise.final_suspend() does not throw

Summary:
This patch addresses https://bugs.llvm.org/show_bug.cgi?id=46256
The spec of coroutine requires that the expression co_­await 
promise.final_­suspend() shall not be potentially-throwing.
To check this, we recursively look at every call (including Call, MemberCall, 
OperatorCall and Constructor) in all code
generated by the final suspend, and ensure that the callees are declared with 
noexcept. We also look at any returned data
type that requires explicit destruction, and check their destructors for 
noexcept.

This patch does not check declarations with dependent types yet, which will be 
done in future patches.

Updated all tests to add noexcept to the required functions, and added a 
dedicated test for this patch.

This patch might start to cause existing codebase fail to compile because most 
people may not have been strict in tagging
all the related functions noexcept.

Reviewers: lewissbaker, modocache, junparser

Reviewed By: modocache

Subscribers: arphaman, junparser, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D82029

Added: 
    clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaCoroutine.cpp
    clang/lib/Sema/SemaExceptionSpec.cpp
    clang/test/AST/Inputs/std-coroutine.h
    clang/test/AST/coroutine-source-location-crash.cpp
    clang/test/Analysis/more-dtors-cfg-output.cpp
    clang/test/CodeGenCXX/ubsan-coroutines.cpp
    clang/test/CodeGenCoroutines/Inputs/coroutine.h
    clang/test/CodeGenCoroutines/coro-alloc.cpp
    clang/test/CodeGenCoroutines/coro-always-inline.cpp
    clang/test/CodeGenCoroutines/coro-await-domination.cpp
    clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
    clang/test/CodeGenCoroutines/coro-await.cpp
    clang/test/CodeGenCoroutines/coro-dest-slot.cpp
    clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
    clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
    clang/test/CodeGenCoroutines/coro-params.cpp
    clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
    clang/test/CodeGenCoroutines/coro-ret-void.cpp
    clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
    clang/test/CodeGenCoroutines/coro-return.cpp
    clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
    clang/test/Index/coroutines.cpp
    clang/test/SemaCXX/Inputs/std-coroutine.h
    clang/test/SemaCXX/co_await-range-for.cpp
    clang/test/SemaCXX/coreturn-eh.cpp
    clang/test/SemaCXX/coreturn.cpp
    clang/test/SemaCXX/coroutine-rvo.cpp
    clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
    clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
    clang/test/SemaCXX/coroutines.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d6d0ccaa00be..66856834a98f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10523,7 +10523,13 @@ def err_await_suspend_invalid_return_type : Error<
 def note_await_ready_no_bool_conversion : Note<
   "return type of 'await_ready' is required to be contextually convertible to 
'bool'"
 >;
-}
+def err_coroutine_promise_final_suspend_requires_nothrow : Error<
+  "the expression 'co_await __promise.final_suspend()' is required to be 
non-throwing"
+>;
+def note_coroutine_function_declare_noexcept : Note<
+  "must be declared with 'noexcept'"
+>;
+} // end of coroutines issue category
 
 let CategoryName = "Documentation Issue" in {
 def warn_not_a_doxygen_trailing_member_comment : Warning<

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 8c8e981e6065..88dd0d453883 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1697,6 +1697,10 @@ class Sema final {
   static QualType GetTypeFromParser(ParsedType Ty,
                                     TypeSourceInfo **TInfo = nullptr);
   CanThrowResult canThrow(const Stmt *E);
+  /// Determine whether the callee of a particular function call can throw.
+  /// E, D and Loc are all optional.
+  static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+                                       SourceLocation Loc = SourceLocation());
   const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
                                                 const FunctionProtoType *FPT);
   void UpdateExceptionSpec(FunctionDecl *FD,

diff  --git a/clang/lib/Sema/SemaCoroutine.cpp 
b/clang/lib/Sema/SemaCoroutine.cpp
index 5ed0bbd6041d..c8ca247aae83 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -24,6 +24,7 @@
 #include "clang/Sema/Overload.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/SmallSet.h"
 
 using namespace clang;
 using namespace sema;
@@ -604,6 +605,72 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, 
SourceLocation Loc,
   return ScopeInfo;
 }
 
+/// Recursively check \p E and all its children to see if any call target
+/// (including constructor call) is declared noexcept. Also any value returned
+/// from the call has a noexcept destructor.
+static void checkNoThrow(Sema &S, const Stmt *E,
+                         llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) {
+  auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
+    // In the case of dtor, the call to dtor is implicit and hence we should
+    // pass nullptr to canCalleeThrow.
+    if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
+      if (ThrowingDecls.empty()) {
+        // First time seeing an error, emit the error message.
+        S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(),
+               diag::err_coroutine_promise_final_suspend_requires_nothrow);
+      }
+      ThrowingDecls.insert(D);
+    }
+  };
+  auto SC = E->getStmtClass();
+  if (SC == Expr::CXXConstructExprClass) {
+    auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor();
+    checkDeclNoexcept(Ctor);
+    // Check the corresponding destructor of the constructor.
+    checkDeclNoexcept(Ctor->getParent()->getDestructor(), true);
+  } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
+             SC == Expr::CXXOperatorCallExprClass) {
+    if (!cast<CallExpr>(E)->isTypeDependent()) {
+      // FIXME: Handle dependent types.
+      checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl());
+      auto ReturnType = 
cast<CallExpr>(E)->getCallReturnType(S.getASTContext());
+      // Check the destructor of the call return type, if any.
+      if (ReturnType.isDestructedType() ==
+          QualType::DestructionKind::DK_cxx_destructor) {
+        const auto *T =
+            cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
+        checkDeclNoexcept(
+            dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true);
+      }
+    }
+  }
+  for (const auto *Child : E->children()) {
+    if (!Child)
+      continue;
+    checkNoThrow(S, Child, ThrowingDecls);
+  }
+}
+
+/// Check that the expression co_await promise.final_suspend() shall not be
+/// potentially-throwing.
+static bool checkNoThrow(Sema &S, const Stmt *FinalSuspend) {
+  llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls;
+  // We first collect all declarations that should not throw but not declared
+  // with noexcept. We then sort them based on the location before printing.
+  // This is to avoid emitting the same note multiple times on the same
+  // declaration, and also provide a deterministic order for the messages.
+  checkNoThrow(S, FinalSuspend, ThrowingDecls);
+  auto SortedDecls = llvm::SmallVector<const Decl *, 4>{ThrowingDecls.begin(),
+                                                        ThrowingDecls.end()};
+  sort(SortedDecls, [](const Decl *A, const Decl *B) {
+    return A->getEndLoc() < B->getEndLoc();
+  });
+  for (const auto *D : SortedDecls) {
+    S.Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept);
+  }
+  return ThrowingDecls.empty();
+}
+
 bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
                                    StringRef Keyword) {
   if (!checkCoroutineContext(*this, KWLoc, Keyword))
@@ -646,7 +713,7 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, 
SourceLocation KWLoc,
     return true;
 
   StmtResult FinalSuspend = buildSuspends("final_suspend");
-  if (FinalSuspend.isInvalid())
+  if (FinalSuspend.isInvalid() || !checkNoThrow(*this, FinalSuspend.get()))
     return true;
 
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp 
b/clang/lib/Sema/SemaExceptionSpec.cpp
index 504a48b56639..d7695f9d7d7a 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -999,10 +999,8 @@ static CanThrowResult canSubStmtsThrow(Sema &Self, const 
Stmt *S) {
   return R;
 }
 
-/// Determine whether the callee of a particular function call can throw.
-/// E and D are both optional, but at least one of E and Loc must be specified.
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
-                                     SourceLocation Loc = SourceLocation()) {
+CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+                                    SourceLocation Loc) {
   // As an extension, we assume that __attribute__((nothrow)) functions don't
   // throw.
   if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -1048,7 +1046,8 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr 
*E, const Decl *D,
   if (!FT)
     return CT_Can;
 
-  FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
+  if (Loc.isValid() || (Loc.isInvalid() && E))
+    FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
   if (!FT)
     return CT_Can;
 
@@ -1069,7 +1068,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const 
VarDecl *VD) {
             VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
       if (auto *Dtor = RD->getDestructor()) {
         CT = mergeCanThrow(
-            CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+            CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
       }
     }
   }

diff  --git a/clang/test/AST/Inputs/std-coroutine.h 
b/clang/test/AST/Inputs/std-coroutine.h
index 7a424f1e99cf..c1be9a19b810 100644
--- a/clang/test/AST/Inputs/std-coroutine.h
+++ b/clang/test/AST/Inputs/std-coroutine.h
@@ -10,12 +10,12 @@ struct coroutine_traits { using promise_type = typename 
Ret::promise_type; };
 
 template <class Promise = void>
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle<void> {
   template <class PromiseType>
-  coroutine_handle(coroutine_handle<PromiseType>);
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
   static coroutine_handle from_address(void *);
 };
 
@@ -26,9 +26,9 @@ struct suspend_always {
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  void await_suspend(coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 
 } // namespace experimental

diff  --git a/clang/test/AST/coroutine-source-location-crash.cpp 
b/clang/test/AST/coroutine-source-location-crash.cpp
index 24fe3bcb224e..6c0184d2076d 100644
--- a/clang/test/AST/coroutine-source-location-crash.cpp
+++ b/clang/test/AST/coroutine-source-location-crash.cpp
@@ -24,7 +24,7 @@ struct coro_t {
   struct promise_type {
     coro_t get_return_object();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     void return_void();
     static void unhandled_exception();
   };

diff  --git a/clang/test/Analysis/more-dtors-cfg-output.cpp 
b/clang/test/Analysis/more-dtors-cfg-output.cpp
index c0df5953aa6e..668210a0f61e 100644
--- a/clang/test/Analysis/more-dtors-cfg-output.cpp
+++ b/clang/test/Analysis/more-dtors-cfg-output.cpp
@@ -278,16 +278,16 @@ void new_default_ctor_with_default_arg(long count) {
 namespace std::experimental {
   template <typename Promise>
   struct coroutine_handle {
-    static coroutine_handle from_address(void *);
+    static coroutine_handle from_address(void *) noexcept;
   };
 }
 
 struct TestPromise {
   TestPromise initial_suspend();
-  TestPromise final_suspend();
-  bool await_ready();
-  void await_suspend(const std::experimental::coroutine_handle<TestPromise> &);
-  void await_resume();
+  TestPromise final_suspend() noexcept;
+  bool await_ready() noexcept;
+  void await_suspend(const std::experimental::coroutine_handle<TestPromise> &) 
noexcept;
+  void await_resume() noexcept;
   Foo return_value(const Bar &);
   Bar get_return_object();
   void unhandled_exception();

diff  --git a/clang/test/CodeGenCXX/ubsan-coroutines.cpp 
b/clang/test/CodeGenCXX/ubsan-coroutines.cpp
index 8728c1511122..dacc229ce519 100644
--- a/clang/test/CodeGenCXX/ubsan-coroutines.cpp
+++ b/clang/test/CodeGenCXX/ubsan-coroutines.cpp
@@ -32,7 +32,7 @@ struct task {
   struct promise_type {
     task get_return_object() { return task(); }
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception() {}
   };

diff  --git a/clang/test/CodeGenCoroutines/Inputs/coroutine.h 
b/clang/test/CodeGenCoroutines/Inputs/coroutine.h
index d58212b1d528..5cc78a4904aa 100644
--- a/clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ b/clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -72,9 +72,9 @@ struct suspend_always {
   void await_resume() {}
 };
 struct suspend_never {
-  bool await_ready() { return true; }
-  void await_suspend(coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 
 }}}

diff  --git a/clang/test/CodeGenCoroutines/coro-alloc.cpp 
b/clang/test/CodeGenCoroutines/coro-alloc.cpp
index a73b7d85a4be..bf8edf012a33 100644
--- a/clang/test/CodeGenCoroutines/coro-alloc.cpp
+++ b/clang/test/CodeGenCoroutines/coro-alloc.cpp
@@ -10,7 +10,7 @@ struct coroutine_traits; // expected-note {{declared here}}
 template <class Promise = void>
 struct coroutine_handle {
   coroutine_handle() = default;
-  static coroutine_handle from_address(void *) { return {}; }
+  static coroutine_handle from_address(void *) noexcept { return {}; }
 };
 
 template <>
@@ -18,7 +18,7 @@ struct coroutine_handle<void> {
   static coroutine_handle from_address(void *) { return {}; }
   coroutine_handle() = default;
   template <class PromiseType>
-  coroutine_handle(coroutine_handle<PromiseType>) {}
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
 };
 
 } // end namespace experimental
@@ -36,9 +36,9 @@ void  operator delete(void* __p, const std::nothrow_t&) 
noexcept;
 
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  void await_suspend(std::experimental::coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 
 struct global_new_delete_tag {};
@@ -48,7 +48,7 @@ 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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -89,7 +89,7 @@ struct std::experimental::coroutine_traits<void, 
promise_new_tag> {
     void *operator new(unsigned long);
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -115,7 +115,7 @@ struct std::experimental::coroutine_traits<void, 
promise_matching_placement_new_
                        int, float, double);
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -145,7 +145,7 @@ struct std::experimental::coroutine_traits<void, 
promise_matching_global_placeme
   struct promise_type {
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -168,7 +168,7 @@ struct std::experimental::coroutine_traits<void, 
promise_delete_tag> {
     void operator delete(void*);
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -193,7 +193,7 @@ struct std::experimental::coroutine_traits<void, 
promise_sized_delete_tag> {
     void operator delete(void*, unsigned long);
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
   };
 };
@@ -218,7 +218,7 @@ 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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     static int get_return_object_on_allocation_failure() { return -1; }
   };

diff  --git a/clang/test/CodeGenCoroutines/coro-always-inline.cpp 
b/clang/test/CodeGenCoroutines/coro-always-inline.cpp
index a2e4bba45c0c..e4aa14a6ac39 100644
--- a/clang/test/CodeGenCoroutines/coro-always-inline.cpp
+++ b/clang/test/CodeGenCoroutines/coro-always-inline.cpp
@@ -14,22 +14,22 @@ namespace experimental {
 struct handle {};
 
 struct awaitable {
-  bool await_ready() { return true; }
+  bool await_ready() noexcept { return true; }
   // CHECK-NOT: await_suspend
-  inline void __attribute__((__always_inline__)) await_suspend(handle) {}
-  bool await_resume() { return true; }
+  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) { return {}; }
+  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() { return {}; }
+    awaitable final_suspend() noexcept { return {}; }
     void return_void() {}
     T get_return_object() { return T(); }
     void unhandled_exception() {}

diff  --git a/clang/test/CodeGenCoroutines/coro-await-domination.cpp 
b/clang/test/CodeGenCoroutines/coro-await-domination.cpp
index 5df22374a6e7..3ce8cd7a6227 100644
--- a/clang/test/CodeGenCoroutines/coro-await-domination.cpp
+++ b/clang/test/CodeGenCoroutines/coro-await-domination.cpp
@@ -7,7 +7,7 @@ struct coro {
   struct promise_type {
     coro get_return_object();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     void return_void();
     static void unhandled_exception();
   };
@@ -35,4 +35,3 @@ extern "C" coro f(int) {
   x = co_await A{};
   consume(x);
 }
-

diff  --git a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp 
b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
index f0f8855fbd4d..b5dcc3f9da78 100644
--- a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
+++ b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
@@ -22,7 +22,7 @@ struct throwing_task {
   struct promise_type {
     auto get_return_object() { return throwing_task{}; }
     auto initial_suspend() { return throwing_awaitable{}; }
-    auto final_suspend() { return coro::suspend_never{}; }
+    auto final_suspend() noexcept { return coro::suspend_never{}; }
     void return_void() {}
     void unhandled_exception() {}
   };
@@ -76,7 +76,7 @@ throwing_task f() {
   // CHECK-NEXT: br label %[[COROFINAL]]
 
   // CHECK: [[COROFINAL]]:
-  // CHECK-NEXT: invoke void @_ZN13throwing_task12promise_type13final_suspendEv
+  // CHECK-NEXT: call void @_ZN13throwing_task12promise_type13final_suspendEv
   co_return;
 }
 
@@ -90,7 +90,7 @@ struct noexcept_task {
   struct promise_type {
     auto get_return_object() { return noexcept_task{}; }
     auto initial_suspend() { return noexcept_awaitable{}; }
-    auto final_suspend() { return coro::suspend_never{}; }
+    auto final_suspend() noexcept { return coro::suspend_never{}; }
     void return_void() {}
     void unhandled_exception() {}
   };

diff  --git a/clang/test/CodeGenCoroutines/coro-await.cpp 
b/clang/test/CodeGenCoroutines/coro-await.cpp
index acd3c4aa9716..90da9be5976d 100644
--- a/clang/test/CodeGenCoroutines/coro-await.cpp
+++ b/clang/test/CodeGenCoroutines/coro-await.cpp
@@ -17,7 +17,7 @@ struct coroutine_handle<void> {
 
 template <typename Promise>
 struct coroutine_handle : coroutine_handle<> {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 
 }
@@ -29,9 +29,9 @@ struct init_susp {
   void await_resume();
 };
 struct final_susp {
-  bool await_ready();
-  void await_suspend(std::experimental::coroutine_handle<>);
-  void await_resume();
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
 };
 
 struct suspend_always {
@@ -46,7 +46,7 @@ struct std::experimental::coroutine_traits<void> {
   struct promise_type {
     void get_return_object();
     init_susp initial_suspend();
-    final_susp final_suspend();
+    final_susp final_suspend() noexcept;
     void return_void();
   };
 };
@@ -119,7 +119,7 @@ struct std::experimental::coroutine_traits<void,int> {
   struct promise_type {
     void get_return_object();
     init_susp initial_suspend();
-    final_susp final_suspend();
+    final_susp final_suspend() noexcept;
     void return_void();
     suspend_maybe yield_value(int);
   };
@@ -295,7 +295,7 @@ struct std::experimental::coroutine_traits<void,double> {
   struct promise_type {
     void get_return_object();
     init_susp initial_suspend();
-    final_susp final_suspend();
+    final_susp final_suspend() noexcept;
     void return_void();
     AwaitResumeReturnsLValue yield_value(int);
   };

diff  --git a/clang/test/CodeGenCoroutines/coro-dest-slot.cpp 
b/clang/test/CodeGenCoroutines/coro-dest-slot.cpp
index 4c7395ba608c..0c8ef6b04582 100644
--- a/clang/test/CodeGenCoroutines/coro-dest-slot.cpp
+++ b/clang/test/CodeGenCoroutines/coro-dest-slot.cpp
@@ -8,7 +8,7 @@ struct coro {
   struct promise_type {
     coro get_return_object();
     suspend_always initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     void return_void();
     static void unhandled_exception();
   };

diff  --git a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp 
b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
index 42856f4479ec..787cb01a53e6 100644
--- a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
+++ b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
@@ -21,7 +21,7 @@ template <class RetObject>
 struct promise_type {
     RetObject get_return_object();
     suspend_always initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     void return_void();
     static void unhandled_exception();
 };
@@ -52,7 +52,7 @@ 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();
+    suspend_never final_suspend() noexcept;
     void return_void();
     static void unhandled_exception();
 };

diff  --git a/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp 
b/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
index cea71a1acc6b..2a1b0d34658f 100644
--- a/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
+++ b/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
@@ -33,19 +33,19 @@ namespace experimental {
 struct handle {};
 
 struct awaitable {
-  bool await_ready() { return true; }
-  void await_suspend(handle) {}
-  bool await_resume() { return true; }
+  bool await_ready() noexcept { return true; }
+  void await_suspend(handle) noexcept {}
+  bool await_resume() noexcept { return true; }
 };
 
 template <typename T> struct coroutine_handle {
-  static handle from_address(void *address) { return {}; }
+  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() { return {}; }
+    awaitable final_suspend() noexcept { return {}; }
     void return_void() {}
     T get_return_object() { return T(); }
     void unhandled_exception() {}

diff  --git a/clang/test/CodeGenCoroutines/coro-params.cpp 
b/clang/test/CodeGenCoroutines/coro-params.cpp
index 1302d734d444..5f8b28b40b2b 100644
--- a/clang/test/CodeGenCoroutines/coro-params.cpp
+++ b/clang/test/CodeGenCoroutines/coro-params.cpp
@@ -142,7 +142,7 @@ struct std::experimental::coroutine_traits<void, 
promise_matching_constructor, i
     promise_type() = delete;
     void get_return_object() {}
     suspend_always initial_suspend() { return {}; }
-    suspend_always final_suspend() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception() {}
   };
@@ -166,7 +166,7 @@ template <typename... Args> struct 
std::experimental::coroutine_traits<method, A
     promise_type(some_class&, float);
     method get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void return_void();
     void unhandled_exception();
   };

diff  --git a/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp 
b/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
index bc190c9d1cb5..4fb0f0fef794 100644
--- a/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
+++ b/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
@@ -11,7 +11,7 @@ struct coro_t {
   struct promise_type {
     coro_t get_return_object();
     coro::suspend_never initial_suspend();
-    coro::suspend_never final_suspend();
+    coro::suspend_never final_suspend() noexcept;
     void return_void();
     promise_type();
     ~promise_type();

diff  --git a/clang/test/CodeGenCoroutines/coro-ret-void.cpp 
b/clang/test/CodeGenCoroutines/coro-ret-void.cpp
index 6ebb44dfaefa..0007c36fa942 100644
--- a/clang/test/CodeGenCoroutines/coro-ret-void.cpp
+++ b/clang/test/CodeGenCoroutines/coro-ret-void.cpp
@@ -8,7 +8,7 @@ struct coro1 {
   struct promise_type {
     coro1 get_return_object();
     coro::suspend_never initial_suspend();
-    coro::suspend_never final_suspend();
+    coro::suspend_never final_suspend() noexcept;
     void return_void();
   };
 };
@@ -39,7 +39,7 @@ struct coro2 {
   struct promise_type {
     coro2 get_return_object();
     coro::suspend_never initial_suspend();
-    coro::suspend_never final_suspend();
+    coro::suspend_never final_suspend() noexcept;
     void return_value(int);
   };
 };

diff  --git a/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp 
b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
index 8526b6f8a8da..8bd6c79b497d 100644
--- a/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
+++ b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
@@ -14,7 +14,7 @@ template <>
 struct coroutine_handle<> {};
 template <typename>
 struct coroutine_handle : coroutine_handle<> {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 struct e {
   int await_ready();
@@ -29,13 +29,13 @@ template <typename>
 struct f;
 struct g {
   struct h {
-    int await_ready();
+    int await_ready() noexcept;
     template <typename al>
-    void await_suspend(std::experimental::coroutine_handle<al>);
-    void await_resume();
+    void await_suspend(std::experimental::coroutine_handle<al>) noexcept;
+    void await_resume() noexcept;
   };
   std::experimental::e initial_suspend();
-  h final_suspend();
+  h final_suspend() noexcept;
   template <typename ag>
   auto await_transform(ag) { return ah(ag()); }
 };

diff  --git a/clang/test/CodeGenCoroutines/coro-return.cpp 
b/clang/test/CodeGenCoroutines/coro-return.cpp
index 17356f944ce1..65c0655b8679 100644
--- a/clang/test/CodeGenCoroutines/coro-return.cpp
+++ b/clang/test/CodeGenCoroutines/coro-return.cpp
@@ -5,27 +5,27 @@ template <typename... T> struct coroutine_traits;
 
 template <class Promise = void> struct coroutine_handle {
   coroutine_handle() = default;
-  static coroutine_handle from_address(void *) { return {}; }
+  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>) {}
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
 };
 }
 
 struct suspend_always {
-  bool await_ready();
-  void await_suspend(std::experimental::coroutine_handle<>);
-  void await_resume();
+  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();
+    suspend_always final_suspend() noexcept;
     void return_void();
   };
 };
@@ -44,7 +44,7 @@ struct std::experimental::coroutine_traits<int> {
   struct promise_type {
     int get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void return_value(int);
   };
 };

diff  --git a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp 
b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
index 039f02352cfc..870e67477ed1 100644
--- a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
+++ b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
@@ -17,7 +17,7 @@ struct coro_t {
       return {};
     }
     coro::suspend_never initial_suspend() { return {}; }
-    coro::suspend_never final_suspend() { return {}; }
+    coro::suspend_never final_suspend() noexcept { return {}; }
     void return_void(){}
     void unhandled_exception() noexcept;
   };
@@ -48,11 +48,9 @@ coro_t f() {
 // CHECK: [[CATCHRETDEST]]:
 // CHECK-NEXT: br label %[[TRYCONT:.+]]
 // CHECK: [[TRYCONT]]:
-// CHECK-NEXT: br label %[[RESUMECONT:.+]]
-// CHECK: [[RESUMECONT]]:
 // CHECK-NEXT: br label %[[COROFIN:.+]]
 // CHECK: [[COROFIN]]:
-// CHECK-NEXT: invoke void 
@"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
+// CHECK-NEXT: call void 
@"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
 
 // CHECK-LPAD: @_Z1fv(
 // CHECK-LPAD:   invoke void @_Z9may_throwv()
@@ -69,8 +67,6 @@ coro_t f() {
 // CHECK-LPAD: [[CATCHRETDEST]]:
 // CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]]
 // CHECK-LPAD: [[TRYCONT]]:
-// CHECK-LPAD: br label %[[RESUMECONT:.+]]
-// CHECK-LPAD: [[RESUMECONT]]:
-// CHECK-LPAD-NEXT: br label %[[COROFIN:.+]]
+// CHECK-LPAD: br label %[[COROFIN:.+]]
 // CHECK-LPAD: [[COROFIN]]:
-// CHECK-LPAD-NEXT: invoke void @_ZN6coro_t12promise_type13final_suspendEv(
+// CHECK-LPAD-NEXT: call void @_ZN6coro_t12promise_type13final_suspendEv(

diff  --git a/clang/test/Index/coroutines.cpp b/clang/test/Index/coroutines.cpp
index 5853437926c6..000327ffaec4 100644
--- a/clang/test/Index/coroutines.cpp
+++ b/clang/test/Index/coroutines.cpp
@@ -7,7 +7,7 @@ using std::experimental::suspend_never;
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };

diff  --git a/clang/test/SemaCXX/Inputs/std-coroutine.h 
b/clang/test/SemaCXX/Inputs/std-coroutine.h
index 7a424f1e99cf..e9af21aa5194 100644
--- a/clang/test/SemaCXX/Inputs/std-coroutine.h
+++ b/clang/test/SemaCXX/Inputs/std-coroutine.h
@@ -10,25 +10,25 @@ struct coroutine_traits { using promise_type = typename 
Ret::promise_type; };
 
 template <class Promise = void>
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle<void> {
   template <class PromiseType>
-  coroutine_handle(coroutine_handle<PromiseType>);
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
   static coroutine_handle from_address(void *);
 };
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  void await_suspend(coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  void await_suspend(coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 
 } // namespace experimental

diff  --git a/clang/test/SemaCXX/co_await-range-for.cpp 
b/clang/test/SemaCXX/co_await-range-for.cpp
index 4d999ea7db5e..b6c6e6c40f97 100644
--- a/clang/test/SemaCXX/co_await-range-for.cpp
+++ b/clang/test/SemaCXX/co_await-range-for.cpp
@@ -44,7 +44,7 @@ struct MyForLoopArrayAwaiter {
     void return_void();
     void unhandled_exception();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     template <class T>
     Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly 
deleted}}
   };
@@ -62,7 +62,7 @@ struct ForLoopAwaiterBadBeginTransform {
     void return_void();
     void unhandled_exception();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
 
     template <class T>
     Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ 
{{explicitly deleted}}
@@ -96,7 +96,7 @@ struct ForLoopAwaiterBadIncTransform {
     void return_void();
     void unhandled_exception();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
 
     template <class T>
     Awaiter<T> await_transform(BeginTag<T> e);
@@ -137,7 +137,7 @@ struct ForLoopAwaiterCoawaitLookup {
     void return_void();
     void unhandled_exception();
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     template <class T>
     CoawaitTag<T, false> await_transform(BeginTag<T> e);
     template <class T>

diff  --git a/clang/test/SemaCXX/coreturn-eh.cpp 
b/clang/test/SemaCXX/coreturn-eh.cpp
index 79065736c0a4..591ab8ec5c5e 100644
--- a/clang/test/SemaCXX/coreturn-eh.cpp
+++ b/clang/test/SemaCXX/coreturn-eh.cpp
@@ -17,7 +17,7 @@ struct object { ~object() {} };
 struct promise_void_return_value {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_value(object);
 };
@@ -26,7 +26,7 @@ struct VoidTagReturnValue {
   struct promise_type {
     VoidTagReturnValue get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void unhandled_exception();
     void return_value(object);
   };

diff  --git a/clang/test/SemaCXX/coreturn.cpp b/clang/test/SemaCXX/coreturn.cpp
index 4d8bfa11d832..eaa462016de5 100644
--- a/clang/test/SemaCXX/coreturn.cpp
+++ b/clang/test/SemaCXX/coreturn.cpp
@@ -13,7 +13,7 @@ struct awaitable {
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -21,7 +21,7 @@ struct promise_void {
 struct promise_void_return_value {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_value(int);
 };
@@ -30,7 +30,7 @@ struct VoidTagNoReturn {
   struct promise_type {
     VoidTagNoReturn get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void unhandled_exception();
   };
 };
@@ -39,7 +39,7 @@ struct VoidTagReturnValue {
   struct promise_type {
     VoidTagReturnValue get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void unhandled_exception();
     void return_value(int);
   };
@@ -49,7 +49,7 @@ struct VoidTagReturnVoid {
   struct promise_type {
     VoidTagReturnVoid get_return_object();
     suspend_always initial_suspend();
-    suspend_always final_suspend();
+    suspend_always final_suspend() noexcept;
     void unhandled_exception();
     void return_void();
   };
@@ -58,7 +58,7 @@ struct VoidTagReturnVoid {
 struct promise_float {
   float get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -66,7 +66,7 @@ struct promise_float {
 struct promise_int {
   int get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_value(int);
   void unhandled_exception();
 };

diff  --git a/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp 
b/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
new file mode 100644
index 000000000000..d234d8adf7c9
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
@@ -0,0 +1,62 @@
+// 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; };
+
+template <class Promise = void>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *); // expected-note {{must be 
declared with 'noexcept'}}
+};
+template <>
+struct coroutine_handle<void> {
+  template <class PromiseType>
+  coroutine_handle(coroutine_handle<PromiseType>); // expected-note {{must be 
declared with 'noexcept'}}
+};
+
+struct suspend_never {
+  bool await_ready() { return true; }       // expected-note {{must be 
declared with 'noexcept'}}
+  void await_suspend(coroutine_handle<>) {} // expected-note {{must be 
declared with 'noexcept'}}
+  void await_resume() {}                    // expected-note {{must be 
declared with 'noexcept'}}
+  ~suspend_never() noexcept(false);         // expected-note {{must be 
declared with 'noexcept'}}
+};
+
+struct suspend_always {
+  bool await_ready() { return false; }
+  void await_suspend(coroutine_handle<>) {}
+  void await_resume() {}
+  suspend_never operator co_await(); // expected-note {{must be declared with 
'noexcept'}}
+  ~suspend_always() noexcept(false); // expected-note {{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_never initial_suspend();
+    suspend_always final_suspend(); // expected-note {{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;
+}

diff  --git a/clang/test/SemaCXX/coroutine-rvo.cpp 
b/clang/test/SemaCXX/coroutine-rvo.cpp
index 8521b8506fd0..1cd025052dca 100644
--- a/clang/test/SemaCXX/coroutine-rvo.cpp
+++ b/clang/test/SemaCXX/coroutine-rvo.cpp
@@ -49,7 +49,7 @@ template <typename T>
 struct task {
   struct promise_type {
     auto initial_suspend() { return suspend_never{}; }
-    auto final_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) {}

diff  --git a/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp 
b/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
index d819580462c8..88fae2e8acb2 100644
--- a/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
+++ b/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
@@ -23,7 +23,7 @@ struct promise_void {
 #endif
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
 };
 

diff  --git a/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp 
b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
index 5bdb232d5307..391f64d37e5b 100644
--- a/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
+++ b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
@@ -16,7 +16,7 @@ struct coro_t {
   struct promise_type {
     coro_t get_return_object() { return {}; }
     suspend_never initial_suspend() { return {}; }
-    suspend_never final_suspend() { return {}; }
+    suspend_never final_suspend() noexcept { return {}; }
     A yield_value(int) { return {}; }
     void return_void() {}
     static void unhandled_exception() {}

diff  --git a/clang/test/SemaCXX/coroutines.cpp 
b/clang/test/SemaCXX/coroutines.cpp
index 9e94fe8c9c10..f354b1f2a4bb 100644
--- a/clang/test/SemaCXX/coroutines.cpp
+++ b/clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@ struct std::experimental::coroutine_traits<coro<Promise>, 
Ps...> {
 };
 
 struct awaitable {
-  bool await_ready();
-  template <typename F> void await_suspend(F);
-  void await_resume();
+  bool await_ready() noexcept;
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
 } a;
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  template <typename F> void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  template <typename F> void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  template <typename F>
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct auto_await_suspend {
@@ -127,7 +130,7 @@ struct not_awaitable {};
 struct promise {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_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}}
@@ -138,7 +141,7 @@ struct promise {
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -152,13 +155,13 @@ namespace std {
 namespace experimental {
 template <class PromiseType = void>
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle<void> {
   template <class PromiseType>
-  coroutine_handle(coroutine_handle<PromiseType>);
-  static coroutine_handle from_address(void *);
+  coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
 };
 }} // namespace std::experimental
 
@@ -402,7 +405,7 @@ struct await_arg_2 {};
 
 namespace adl_ns {
 struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
 }
 
 namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@ namespace dependent_operator_co_await_lookup {
     typedef transform_awaitable await_arg;
     coro<transform_promise> get_return_object();
     transformed initial_suspend();
-    ::adl_ns::coawait_arg_type final_suspend();
+    ::adl_ns::coawait_arg_type final_suspend() noexcept;
     transformed await_transform(transform_awaitable);
     void unhandled_exception();
     void return_void();
@@ -444,7 +447,7 @@ namespace dependent_operator_co_await_lookup {
     typedef AwaitArg await_arg;
     coro<basic_promise> get_return_object();
     awaitable initial_suspend();
-    awaitable final_suspend();
+    awaitable final_suspend() noexcept;
     void unhandled_exception();
     void return_void();
   };
@@ -529,7 +532,7 @@ struct std::experimental::coroutine_traits<void, 
yield_fn_tag> {
     void return_value(int());
 
     suspend_never initial_suspend();
-    suspend_never final_suspend();
+    suspend_never final_suspend() noexcept;
     void get_return_object();
     void unhandled_exception();
   };
@@ -563,7 +566,7 @@ namespace placeholder {
 
 struct bad_promise_1 {
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_void();
 };
@@ -573,7 +576,7 @@ coro<bad_promise_1> missing_get_return_object() { // 
expected-error {{no member
 
 struct bad_promise_2 {
   coro<bad_promise_2> get_return_object();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_void();
 };
@@ -588,14 +591,14 @@ struct bad_promise_3 {
   void unhandled_exception();
   void return_void();
 };
-coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member 
named 'final_suspend' in 'bad_promise_3'}}
+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();
+  suspend_always final_suspend() noexcept;
   void return_void();
 };
 // FIXME: This diagnostic is terrible.
@@ -607,7 +610,7 @@ coro<bad_promise_4> bad_initial_suspend() { // 
expected-error {{no member named
 struct bad_promise_5 {
   coro<bad_promise_5> get_return_object();
   suspend_always initial_suspend();
-  not_awaitable final_suspend();
+  not_awaitable final_suspend() noexcept;
   void return_void();
 };
 // FIXME: This diagnostic is terrible.
@@ -619,7 +622,7 @@ coro<bad_promise_5> bad_final_suspend() { // expected-error 
{{no member named 'a
 struct bad_promise_6 {
   coro<bad_promise_6> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_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}}
@@ -638,7 +641,7 @@ template coro<bad_promise_6> 
bad_implicit_return_dependent(bad_promise_6); // ex
 struct bad_promise_7 { // expected-note 2 {{defined here}}
   coro<bad_promise_7> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_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()'}}
@@ -658,7 +661,7 @@ struct bad_promise_base {
 struct bad_promise_8 : bad_promise_base {
   coro<bad_promise_8> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_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;
@@ -680,7 +683,7 @@ template coro<bad_promise_8> 
calls_unhandled_exception_dependent(bad_promise_8);
 struct bad_promise_9 {
   coro<bad_promise_9> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void await_transform(void *);
   awaitable await_transform(int) __attribute__((unavailable)); // 
expected-note {{explicitly marked unavailable}}
   void return_void();
@@ -693,7 +696,7 @@ coro<bad_promise_9> calls_await_transform() {
 struct bad_promise_10 {
   coro<bad_promise_10> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   int await_transform;
   void return_void();
   void unhandled_exception();
@@ -712,7 +715,7 @@ void ret_void();
 struct good_promise_1 {
   coro<good_promise_1> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   static const call_operator await_transform;
   using Fn = void (*)();
@@ -750,7 +753,7 @@ int main(int, const char**) {
 struct good_promise_2 {
   float get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -783,7 +786,7 @@ 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() { 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();
@@ -797,7 +800,7 @@ extern "C" int f(promise_on_alloc_failure_tag) {
 struct bad_promise_11 {
   coro<bad_promise_11> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_void();
 
@@ -820,7 +823,7 @@ template coro<bad_promise_11> 
dependent_private_alloc_failure_handler(bad_promis
 struct bad_promise_12 {
   coro<bad_promise_12> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_void();
   static coro<bad_promise_12> get_return_object_on_allocation_failure();
@@ -842,7 +845,7 @@ template coro<bad_promise_12> 
dependent_throwing_in_class_new(bad_promise_12); /
 struct good_promise_13 {
   coro<good_promise_13> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
   void return_void();
   static coro<good_promise_13> get_return_object_on_allocation_failure();
@@ -860,7 +863,7 @@ 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();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
   void *operator new(SizeT, double, float, int);
@@ -876,7 +879,7 @@ 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();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
   void *operator new(SizeT, coroutine_nonstatic_member_struct &, double);
@@ -886,7 +889,7 @@ 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();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
   void *operator new(SizeT, double, float, int) noexcept;
@@ -903,7 +906,7 @@ 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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception();
   };
@@ -920,7 +923,7 @@ 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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception();
   };
@@ -938,7 +941,7 @@ struct std::experimental::coroutine_traits<int, 
mismatch_gro_type_tag3> {
     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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception();
   };
@@ -957,7 +960,7 @@ struct std::experimental::coroutine_traits<int, 
mismatch_gro_type_tag4> {
     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() { return {}; }
+    suspend_always final_suspend() noexcept { return {}; }
     void return_void() {}
     void unhandled_exception();
   };
@@ -971,7 +974,7 @@ extern "C" int f(mismatch_gro_type_tag4) {
 struct bad_promise_no_return_func { // expected-note 
{{'bad_promise_no_return_func' defined here}}
   coro<bad_promise_no_return_func> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void unhandled_exception();
 };
 // FIXME: The PDTS currently specifies this as UB, technically forbidding a
@@ -1083,7 +1086,7 @@ struct CoroMemberPromise {
 
   CoroMemberTag get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
 
   AwaitTestT yield_value(int);
 
@@ -1292,7 +1295,7 @@ struct bad_promise_deleted_constructor {
   bad_promise_deleted_constructor() = delete;
   coro<bad_promise_deleted_constructor> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -1314,7 +1317,7 @@ struct good_promise_default_constructor {
   good_promise_default_constructor() = default;
   coro<good_promise_default_constructor> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -1332,7 +1335,7 @@ struct good_promise_custom_constructor {
   good_promise_custom_constructor() = delete;
   coro<good_promise_custom_constructor> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -1359,7 +1362,7 @@ struct bad_promise_no_matching_constructor {
   bad_promise_no_matching_constructor() = delete;
   coro<bad_promise_no_matching_constructor> get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -1383,26 +1386,25 @@ bad_coroutine_calls_with_no_matching_constructor(int, 
int, int) {
 class awaitable_no_unused_warn {
 public:
   using handle_type = std::experimental::coroutine_handle<>;
-  constexpr bool await_ready()  { return false; }
+  constexpr bool await_ready() noexcept { return false; }
   void await_suspend(handle_type) noexcept {}
-  int await_resume() { return 1; }
+  int await_resume() noexcept { return 1; }
 };
 
 
 class awaitable_unused_warn {
 public:
   using handle_type = std::experimental::coroutine_handle<>;
-  constexpr bool await_ready()  { return false; }
+  constexpr bool await_ready() noexcept { return false; }
   void await_suspend(handle_type) noexcept {}
-  [[nodiscard]]
-  int await_resume() { return 1; }
+  [[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();
+  Await final_suspend() noexcept;
   Await yield_value(int);
   void return_void();
   void unhandled_exception();


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to