[Coroutines] Less IR for noexcept await_resume

Summary:
In his review of https://reviews.llvm.org/D45860, @GorNishanov suggested
avoiding generating additional exception-handling IR in the case that
the resume function was marked as 'noexcept', and exceptions could not
occur. This implements that suggestion.

Test Plan: `check-clang`

Reviewers: GorNishanov, EricWF

Reviewed By: GorNishanov

Subscribers: cfe-commits, GorNishanov

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

llvm-svn: 335422
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index bd16896..4f525c8 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -130,6 +130,16 @@
   return Prefix;
 }
 
+static bool memberCallExpressionCanThrow(const Expr *E) {
+  if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
+    if (const auto *Proto =
+            CE->getMethodDecl()->getType()->getAs<FunctionProtoType>())
+      if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
+          Proto->canThrow() == CT_Cannot)
+        return false;
+  return true;
+}
+
 // Emit suspend expression which roughly looks like:
 //
 //   auto && x = CommonExpr();
@@ -217,8 +227,12 @@
 
   // Emit await_resume expression.
   CGF.EmitBlock(ReadyBlock);
+
+  // Exception handling requires additional IR. If the 'await_resume' function
+  // is marked as 'noexcept', we avoid generating this additional IR.
   CXXTryStmt *TryStmt = nullptr;
-  if (Coro.ExceptionHandler && Kind == AwaitKind::Init) {
+  if (Coro.ExceptionHandler && Kind == AwaitKind::Init &&
+      memberCallExpressionCanThrow(S.getResumeExpr())) {
     Coro.ResumeEHVar =
         CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
     Builder.CreateFlagStore(true, Coro.ResumeEHVar);
@@ -625,12 +639,20 @@
     CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
 
     if (CurCoro.Data->ExceptionHandler) {
-      BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
-      BasicBlock *ContBB = createBasicBlock("coro.resumed.cont");
-      Value *SkipBody =
-          Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar, "coro.resumed.eh");
-      Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
-      EmitBlock(BodyBB);
+      // If we generated IR to record whether an exception was thrown from
+      // 'await_resume', then use that IR to determine whether the coroutine
+      // body should be skipped.
+      // If we didn't generate the IR (perhaps because 'await_resume' was marked
+      // as 'noexcept'), then we skip this check.
+      BasicBlock *ContBB = nullptr;
+      if (CurCoro.Data->ResumeEHVar) {
+        BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
+        ContBB = createBasicBlock("coro.resumed.cont");
+        Value *SkipBody = Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar,
+                                                 "coro.resumed.eh");
+        Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
+        EmitBlock(BodyBB);
+      }
 
       auto Loc = S.getLocStart();
       CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr,
@@ -642,7 +664,8 @@
       emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
       ExitCXXTryStmt(*TryStmt);
 
-      EmitBlock(ContBB);
+      if (ContBB)
+        EmitBlock(ContBB);
     }
     else {
       emitBodyAndFallthrough(*this, S, S.getBody());