[coroutines] Include the implicit object parameter type when looking up coroutine_traits for member functions.

This patch was originally from Toby Allsopp, but I hijacked it and
fixed it up with his permission.

llvm-svn: 307513
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index b05c099..05bf531 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -43,9 +43,10 @@
 
 /// Look up the std::coroutine_traits<...>::promise_type for the given
 /// function type.
-static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
-                                  SourceLocation KwLoc,
-                                  SourceLocation FuncLoc) {
+static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
+                                  SourceLocation KwLoc) {
+  const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
+  const SourceLocation FuncLoc = FD->getLocation();
   // FIXME: Cache std::coroutine_traits once we've found it.
   NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
   if (!StdExp) {
@@ -71,16 +72,35 @@
     return QualType();
   }
 
-  // Form template argument list for coroutine_traits<R, P1, P2, ...>.
+  // Form template argument list for coroutine_traits<R, P1, P2, ...> according
+  // to [dcl.fct.def.coroutine]3
   TemplateArgumentListInfo Args(KwLoc, KwLoc);
-  Args.addArgument(TemplateArgumentLoc(
-      TemplateArgument(FnType->getReturnType()),
-      S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc)));
-  // FIXME: If the function is a non-static member function, add the type
-  // of the implicit object parameter before the formal parameters.
-  for (QualType T : FnType->getParamTypes())
+  auto AddArg = [&](QualType T) {
     Args.addArgument(TemplateArgumentLoc(
         TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
+  };
+  AddArg(FnType->getReturnType());
+  // If the function is a non-static member function, add the type
+  // of the implicit object parameter before the formal parameters.
+  if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+    if (MD->isInstance()) {
+      // [over.match.funcs]4
+      // For non-static member functions, the type of the implicit object
+      // parameter is
+      //  — “lvalue reference to cv X” for functions declared without a
+      //    ref-qualifier or with the & ref-qualifier
+      //  — “rvalue reference to cv X” for functions declared with the &&
+      //    ref-qualifier
+      QualType T =
+          MD->getThisType(S.Context)->getAs<PointerType>()->getPointeeType();
+      T = FnType->getRefQualifier() == RQ_RValue
+              ? S.Context.getRValueReferenceType(T)
+              : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
+      AddArg(T);
+    }
+  }
+  for (QualType T : FnType->getParamTypes())
+    AddArg(T);
 
   // Build the template-id.
   QualType CoroTrait =
@@ -424,12 +444,16 @@
 VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
   assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
   auto *FD = cast<FunctionDecl>(CurContext);
+  bool IsThisDependentType = [&] {
+    if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD))
+      return MD->isInstance() && MD->getThisType(Context)->isDependentType();
+    else
+      return false;
+  }();
 
-  QualType T =
-      FD->getType()->isDependentType()
-          ? Context.DependentTy
-          : lookupPromiseType(*this, FD->getType()->castAs<FunctionProtoType>(),
-                              Loc, FD->getLocation());
+  QualType T = FD->getType()->isDependentType() || IsThisDependentType
+                   ? Context.DependentTy
+                   : lookupPromiseType(*this, FD, Loc);
   if (T.isNull())
     return nullptr;