erichkeane updated this revision to Diff 300396.
erichkeane added a comment.

Alright, I have the multi-emit dealt with, and the problems that come with that 
solved.  This doesn't do the MSVC-emit-for-all-CCs thing, but I intend to do 
that in a separate patch with the same infrastructure.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89559/new/

https://reviews.llvm.org/D89559

Files:
  clang/include/clang/AST/DeclCXX.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/DeclCXX.cpp
  clang/lib/AST/MicrosoftMangle.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp
  clang/test/SemaCXX/lambda-conversion-op-cc.cpp

Index: clang/test/SemaCXX/lambda-conversion-op-cc.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/lambda-conversion-op-cc.cpp
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-pc %s -verify -DBAD_CONVERSION
+// RUN: %clang_cc1 -fsyntax-only -triple i386-windows-pc %s -verify -DBAD_CONVERSION -DWIN32
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-pc %s -ast-dump | FileCheck %s --check-prefixes=CHECK,LIN64,NODEF
+// RUN: %clang_cc1 -fsyntax-only -triple i386-windows-pc %s -ast-dump -DWIN32 | FileCheck %s --check-prefixes=CHECK,WIN32,NODEF
+
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-pc -fdefault-calling-conv=vectorcall %s -verify -DBAD_VEC_CONVERS
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-pc -fdefault-calling-conv=vectorcall %s -ast-dump | FileCheck %s --check-prefixes=CHECK,VECTDEF
+
+void useage() {
+  auto normal = [](int, float, double) {};                                // #1
+  auto vectorcall = [](int, float, double) __attribute__((vectorcall)){}; // #2
+#ifdef WIN32
+  auto thiscall = [](int, float, double) __attribute__((thiscall)){}; // #3
+#endif                                                                // WIN32
+  auto cdecl = [](int, float, double) __attribute__((cdecl)){};
+
+  auto genericlambda = [](auto a) {};                                      // #4
+  auto genericvectorcalllambda = [](auto a) __attribute__((vectorcall)){}; // #5
+
+  // None of these should be ambiguous.
+  (void)+normal;
+  (void)+vectorcall;
+#ifdef WIN32
+  (void)+thiscall;
+#endif // WIN32
+  (void)+cdecl;
+
+#ifdef BAD_CONVERSION
+  // expected-error-re@+1 {{invalid argument type {{.*}} to unary expression}}
+  (void)+genericlambda;
+  // expected-error-re@+1 {{invalid argument type {{.*}} to unary expression}}
+  (void)+genericvectorcalllambda;
+#endif // BAD_CONVERSION
+
+  // CHECK: VarDecl {{.*}} normal '
+  // CHECK: LambdaExpr
+  // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((thiscall)) const'
+  // LIN64: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const'
+  // VECTDEF: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const'
+  // NODEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
+  // NODEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
+  // VECTDEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
+  // VECTDEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double) __attribute__((vectorcall))' static inline
+
+  // CHECK: VarDecl {{.*}} vectorcall '
+  // CHECK: LambdaExpr
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((vectorcall)) const'
+  // CHECK: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
+  // CHECK: CXXMethodDecl {{.*}} __invoke 'void (int, float, double) __attribute__((vectorcall))' static inline
+
+  // WIN32: VarDecl {{.*}} thiscall '
+  // WIN32: LambdaExpr
+  // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((thiscall)) const'
+  // WIN32: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
+  // WIN32: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
+
+  // CHECK: VarDecl {{.*}} cdecl '
+  // CHECK: LambdaExpr
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const'
+  // NODEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
+  // NODEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
+  // VECTDEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
+  // VECTDEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double) __attribute__((vectorcall))' static inline
+
+  // CHECK: VarDecl {{.*}} genericlambda '
+  // CHECK: LambdaExpr
+  //
+  // CHECK: FunctionTemplateDecl {{.*}} operator()
+  // LIN64: CXXMethodDecl {{.*}} operator() 'auto (auto) const' inline
+  // LIN64: CXXMethodDecl {{.*}} operator() 'void (char) const' inline
+  // LIN64: CXXMethodDecl {{.*}} operator() 'void (int) const' inline
+  // WIN32: CXXMethodDecl {{.*}} operator() 'auto (auto) __attribute__((thiscall)) const' inline
+  // WIN32: CXXMethodDecl {{.*}} operator() 'void (char) __attribute__((thiscall)) const' inline
+  // WIN32: CXXMethodDecl {{.*}} operator() 'void (int) __attribute__((thiscall)) const' inline
+  //
+  // NODEF: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0)
+  // VECDEF: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall))
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) 'auto (*() const noexcept)(auto)'
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(char) 'void (*() const noexcept)(char)'
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(int) 'void (*() const noexcept)(int)'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) 'auto (*() __attribute__((thiscall)) const noexcept)(auto)'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(char) 'void (*() __attribute__((thiscall)) const noexcept)(char)'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(int) 'void (*() __attribute__((thiscall)) const noexcept)(int)'
+  // VECDEF: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall)) 'auto (*() const noexcept)(auto)' __attribute__((vectorcall))
+  // VECDEF: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((vectorcall)) 'void (*() const noexcept)(char)' __attribute__((vectorcall))
+  // VECDEF: CXXConversionDecl {{.*}} operator auto (*)(int) __attribute__((vectorcall)) 'void (*() const noexcept)(int)' __attribute__((vectorcall))
+  //
+  // CHECK: FunctionTemplateDecl {{.*}} __invoke
+  // NODEF: CXXMethodDecl {{.*}} __invoke 'auto (auto)'
+  // NODEF: CXXMethodDecl {{.*}} __invoke 'void (char)'
+  // NODEF: CXXMethodDecl {{.*}} __invoke 'void (int)'
+  // VECDEF: CXXMethodDecl {{.*}} __invoke 'auto (auto) __attribute__((vectorcall))'
+  // VECDEF: CXXMethodDecl {{.*}} __invoke 'void (char) __attribute__((vectorcall))'
+  // VECDEF: CXXMethodDecl {{.*}} __invoke 'void (int) __attribute__((vectorcall))'
+  //
+  // ONLY WIN32 has the duplicate here.
+  // WIN32: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((thiscall))
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((thiscall)) 'auto (*() __attribute__((thiscall)) const noexcept)(auto) __attribute__((thiscall))'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((thiscall)) 'void (*() __attribute__((thiscall)) const noexcept)(char) __attribute__((thiscall))'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(int) __attribute__((thiscall)) 'void (*() __attribute__((thiscall)) const noexcept)(int) __attribute__((thiscall))'
+  //
+  // WIN32: FunctionTemplateDecl {{.*}} __invoke
+  // WIN32: CXXMethodDecl {{.*}} __invoke 'auto (auto) __attribute__((thiscall))'
+  // WIN32: CXXMethodDecl {{.*}} __invoke 'void (char) __attribute__((thiscall))'
+  // WIN32: CXXMethodDecl {{.*}} __invoke 'void (int) __attribute__((thiscall))'
+
+  // CHECK: VarDecl {{.*}} genericvectorcalllambda '
+  // CHECK: LambdaExpr
+  // CHECK: FunctionTemplateDecl {{.*}} operator()
+  // CHECK: CXXMethodDecl {{.*}} operator() 'auto (auto) __attribute__((vectorcall)) const' inline
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (char) __attribute__((vectorcall)) const' inline
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) __attribute__((vectorcall)) const' inline
+  // CHECK: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall))
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall)) 'auto (*() const noexcept)(auto) __attribute__((vectorcall))'
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((vectorcall)) 'void (*() const noexcept)(char) __attribute__((vectorcall))'
+  // LIN64: CXXConversionDecl {{.*}} operator auto (*)(int) __attribute__((vectorcall)) 'void (*() const noexcept)(int) __attribute__((vectorcall))'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall)) 'auto (*() __attribute__((thiscall)) const noexcept)(auto) __attribute__((vectorcall))'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((vectorcall)) 'void (*() __attribute__((thiscall)) const noexcept)(char) __attribute__((vectorcall))'
+  // WIN32: CXXConversionDecl {{.*}} operator auto (*)(int) __attribute__((vectorcall)) 'void (*() __attribute__((thiscall)) const noexcept)(int) __attribute__((vectorcall))'
+  // CHECK: FunctionTemplateDecl {{.*}} __invoke
+  // CHECK: CXXMethodDecl {{.*}} __invoke 'auto (auto) __attribute__((vectorcall))'
+  // CHECK: CXXMethodDecl {{.*}} __invoke 'void (char) __attribute__((vectorcall))'
+  // CHECK: CXXMethodDecl {{.*}} __invoke 'void (int) __attribute__((vectorcall))'
+
+  // NODEF: UnaryOperator {{.*}} 'void (*)(int, float, double)' prefix '+'
+  // NODEF-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double)'
+  // NODEF-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double)'
+  // VECTDEF: UnaryOperator {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))' prefix '+'
+  // VECTDEF-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))'
+  // VECTDEF-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double) __attribute__((vectorcall))'
+
+  // CHECK: UnaryOperator {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))' prefix '+'
+  // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))'
+  // CHECK-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double) __attribute__((vectorcall))'
+
+  // WIN32: UnaryOperator {{.*}} 'void (*)(int, float, double)' prefix '+'
+  // WIN32-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double)'
+  // WIN32-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double)'
+
+  // NODEF: UnaryOperator {{.*}} 'void (*)(int, float, double)' prefix '+'
+  // NODEF-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double)'
+  // NODEF-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double)'
+  // VECTDEF: UnaryOperator {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))' prefix '+'
+  // VECTDEF-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int, float, double) __attribute__((vectorcall))'
+  // VECTDEF-NEXT: CXXMemberCallExpr {{.*}}'void (*)(int, float, double) __attribute__((vectorcall))'
+
+#ifdef BAD_CONVERSION
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(int, float, double) __attribute__((vectorcall))}}
+  // expected-note@#1 {{candidate function}}
+  void (*__attribute__((vectorcall)) normal_ptr2)(int, float, double) = normal;
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(int, float, double)}}
+  // expected-note@#2 {{candidate function}}
+  void (*vectorcall_ptr2)(int, float, double) = vectorcall;
+#ifdef WIN32
+  void (*__attribute__((thiscall)) thiscall_ptr2)(int, float, double) = thiscall;
+#endif // WIN32
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(char) __attribute__((vectorcall))'}}
+  // expected-note@#4 {{candidate function}}
+  void(__vectorcall * generic_ptr)(char) = genericlambda;
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(char)}}
+  // expected-note@#5 {{candidate function}}
+  void (*generic_ptr2)(char) = genericvectorcalllambda;
+#endif // BAD_CONVERSION
+
+#ifdef BAD_VEC_CONVERS
+  void (*__attribute__((vectorcall)) normal_ptr2)(int, float, double) = normal;
+  void (*normal_ptr3)(int, float, double) = normal;
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(int, float, double) __attribute__((regcall))}}
+  // expected-note@#1 {{candidate function}}
+  void (*__attribute__((regcall)) normalptr4)(int, float, double) = normal;
+  void (*__attribute__((vectorcall)) vectorcall_ptr2)(int, float, double) = vectorcall;
+  void (*vectorcall_ptr3)(int, float, double) = vectorcall;
+#endif // BAD_VEC_CONVERS
+
+  // Required to force emission of the invoker.
+  void (*normal_ptr)(int, float, double) = normal;
+  void (*__attribute__((vectorcall)) vectorcall_ptr)(int, float, double) = vectorcall;
+#ifdef WIN32
+  void (*thiscall_ptr)(int, float, double) = thiscall;
+#endif // WIN32
+  void (*cdecl_ptr)(int, float, double) = cdecl;
+  void (*generic_ptr3)(char) = genericlambda;
+  void (*generic_ptr4)(int) = genericlambda;
+#ifdef WIN32
+  void (*__attribute__((thiscall)) generic_ptr3b)(char) = genericlambda;
+  void (*__attribute__((thiscall)) generic_ptr4b)(int) = genericlambda;
+#endif
+  void (*__attribute__((vectorcall)) generic_ptr5)(char) = genericvectorcalllambda;
+  void (*__attribute__((vectorcall)) generic_ptr6)(int) = genericvectorcalllambda;
+}
Index: clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/lambda-conversion-op-cc.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,LIN64
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu -DCC="__attribute__((vectorcall))" | FileCheck %s --check-prefixes=CHECK,VECCALL
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-windows-pc -DWIN32 | FileCheck %s --check-prefixes=WIN32
+
+#ifndef CC
+#define CC
+#endif
+
+void usage() {
+  auto lambda = [](int i, float f, double d) CC { return i + f + d; };
+
+  double (*CC fp)(int, float, double) = lambda;
+  fp(0, 1.1, 2.2);
+#ifdef WIN32
+  double (*__attribute__((thiscall)) fp2)(int, float, double) = lambda;
+  fp2(0, 1.1, 2.2);
+#endif // WIN32
+}
+
+// void usage function, calls convrsion operator.
+// LIN64: define void @_Z5usagev()
+// VECCALL: define void @_Z5usagev()
+// WIN32: define dso_local void @"?usage@@YAXXZ"()
+// CHECK: call double (i32, float, double)* @"_ZZ5usagevENK3$_0cvPFdifdEEv"
+// WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6A?A?<auto>@@HMN@ZXZ"
+// WIN32: call x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6E?A?<auto>@@HMN@ZXZ"
+//
+// Conversion operator, returns __invoke.
+// CHECK: define internal double (i32, float, double)* @"_ZZ5usagevENK3$_0cvPFdifdEEv"
+// CHECK: ret double (i32, float, double)* @"_ZZ5usagevEN3$_08__invokeEifd"
+// WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6A?A?<auto>@@HMN@ZXZ"
+// WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CA?A?<auto>@@HMN@Z"
+// WIN32: define internal x86_thiscallcc double (i32, float, double)* @"??B<lambda_0>@?0??usage@@YAXXZ@QBEP6E?A?<auto>@@HMN@ZXZ"
+// WIN32: ret double (i32, float, double)* @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CE?A?<auto>@@HMN@Z"
+//
+// __invoke function, calls operator(). Win32 should call both.
+// LIN64: define internal double @"_ZZ5usagevEN3$_08__invokeEifd"
+// LIN64: call double @"_ZZ5usagevENK3$_0clEifd"
+// VECCALL: define internal x86_vectorcallcc double @"_ZZ5usagevEN3$_08__invokeEifd"
+// VECCALL: call x86_vectorcallcc double @"_ZZ5usagevENK3$_0clEifd"
+// WIN32: define internal double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CA?A?<auto>@@HMN@Z"
+// WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z"
+// WIN32: define internal x86_thiscallcc double @"?__invoke@<lambda_0>@?0??usage@@YAXXZ@CE?A?<auto>@@HMN@Z"
+// WIN32: call x86_thiscallcc double @"??R<lambda_0>@?0??usage@@YAXXZ@QBE?A?<auto>@@HMN@Z"
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5001,8 +5001,12 @@
            "failed to deduce lambda return type");
 
     // Build the new return type from scratch.
+    CallingConv RetTyCC = FD->getReturnType()
+                              ->getPointeeType()
+                              ->castAs<FunctionType>()
+                              ->getCallConv();
     QualType RetType = getLambdaConversionFunctionResultType(
-        CallOp->getType()->castAs<FunctionProtoType>());
+        CallOp->getType()->castAs<FunctionProtoType>(), RetTyCC);
     if (FD->getReturnType()->getAs<PointerType>())
       RetType = Context.getPointerType(RetType);
     else {
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -3645,13 +3645,32 @@
   return true;
 }
 
+// Helper for compareConversionFunctions that gets the FunctionType that the
+// conversion-operator return  value 'points' to, or nullptr.
+static const FunctionType *
+getConversionOpReturnTyAsFunction(CXXConversionDecl *Conv) {
+  const FunctionType *ConvFuncTy = Conv->getType()->castAs<FunctionType>();
+  const PointerType *RetPtrTy =
+      ConvFuncTy->getReturnType()->getAs<PointerType>();
+
+  if (!RetPtrTy)
+    return nullptr;
+
+  return RetPtrTy->getPointeeType()->getAs<FunctionType>();
+}
+
 /// Compare the user-defined conversion functions or constructors
 /// of two user-defined conversion sequences to determine whether any ordering
 /// is possible.
 static ImplicitConversionSequence::CompareKind
 compareConversionFunctions(Sema &S, FunctionDecl *Function1,
                            FunctionDecl *Function2) {
-  if (!S.getLangOpts().ObjC || !S.getLangOpts().CPlusPlus11)
+  CXXConversionDecl *Conv1 = dyn_cast_or_null<CXXConversionDecl>(Function1);
+  CXXConversionDecl *Conv2 = dyn_cast_or_null<CXXConversionDecl>(Function2);
+  if (!Conv1 || !Conv2)
+    return ImplicitConversionSequence::Indistinguishable;
+
+  if (!Conv1->getParent()->isLambda() || !Conv2->getParent()->isLambda())
     return ImplicitConversionSequence::Indistinguishable;
 
   // Objective-C++:
@@ -3660,15 +3679,7 @@
   //   respectively, always prefer the conversion to a function pointer,
   //   because the function pointer is more lightweight and is more likely
   //   to keep code working.
-  CXXConversionDecl *Conv1 = dyn_cast_or_null<CXXConversionDecl>(Function1);
-  if (!Conv1)
-    return ImplicitConversionSequence::Indistinguishable;
-
-  CXXConversionDecl *Conv2 = dyn_cast<CXXConversionDecl>(Function2);
-  if (!Conv2)
-    return ImplicitConversionSequence::Indistinguishable;
-
-  if (Conv1->getParent()->isLambda() && Conv2->getParent()->isLambda()) {
+  if (S.getLangOpts().ObjC && S.getLangOpts().CPlusPlus11) {
     bool Block1 = Conv1->getConversionType()->isBlockPointerType();
     bool Block2 = Conv2->getConversionType()->isBlockPointerType();
     if (Block1 != Block2)
@@ -3676,6 +3687,39 @@
                     : ImplicitConversionSequence::Better;
   }
 
+  // In order to support multiple calling conventions for the lambda conversion
+  // operator (such as when the free and member function calling convention is
+  // different), prefer the 'free' mechanism, followed by the calling-convention
+  // of operator(). The latter is in place to support the MSVC-like solution of
+  // defining ALL of the possible conversions in regards to calling-convention.
+  const FunctionType *Conv1FuncRet = getConversionOpReturnTyAsFunction(Conv1);
+  const FunctionType *Conv2FuncRet = getConversionOpReturnTyAsFunction(Conv2);
+
+  if (Conv1FuncRet && Conv2FuncRet &&
+      Conv1FuncRet->getCallConv() != Conv2FuncRet->getCallConv()) {
+    CallingConv Conv1CC = Conv1FuncRet->getCallConv();
+    CallingConv Conv2CC = Conv2FuncRet->getCallConv();
+
+    CXXMethodDecl *CallOp = Conv2->getParent()->getLambdaCallOperator();
+    const FunctionProtoType *CallOpProto =
+        CallOp->getType()->getAs<FunctionProtoType>();
+
+    CallingConv CallOpCC =
+        CallOp->getType()->getAs<FunctionType>()->getCallConv();
+    CallingConv DefaultFree = S.Context.getDefaultCallingConvention(
+        CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
+    CallingConv DefaultMember = S.Context.getDefaultCallingConvention(
+        CallOpProto->isVariadic(), /*IsCXXMethod=*/true);
+
+    CallingConv PrefOrder[] = {DefaultFree, DefaultMember, CallOpCC};
+    for (CallingConv CC : PrefOrder) {
+      if (Conv1CC == CC)
+        return ImplicitConversionSequence::Better;
+      if (Conv2CC == CC)
+        return ImplicitConversionSequence::Worse;
+    }
+  }
+
   return ImplicitConversionSequence::Indistinguishable;
 }
 
@@ -10153,6 +10197,22 @@
   if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() &&
       !Fn->getAttr<TargetAttr>()->isDefaultVersion())
     return;
+  if (isa<CXXConversionDecl>(Fn) &&
+      cast<CXXRecordDecl>(Fn->getParent())->isLambda()) {
+    // Don't print candidates other than the one that matches the calling
+    // convention of the call operator, since that is guaranteed to exist.
+    const auto *RD = cast<CXXRecordDecl>(Fn->getParent());
+    CXXMethodDecl *CallOp = RD->getLambdaCallOperator();
+    CallingConv CallOpCC =
+        CallOp->getType()->getAs<FunctionType>()->getCallConv();
+    CXXConversionDecl *ConvD = cast<CXXConversionDecl>(Fn);
+    QualType ConvRTy = ConvD->getType()->getAs<FunctionType>()->getReturnType();
+    CallingConv ConvToCC =
+        ConvRTy->getPointeeType()->getAs<FunctionType>()->getCallConv();
+
+    if (ConvToCC != CallOpCC)
+      return;
+  }
 
   std::string FnDesc;
   std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair =
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1263,30 +1263,41 @@
   PopFunctionScopeInfo();
 }
 
+static llvm::SmallVector<CallingConv, 2>
+getLambdaConversionFunctionCallConv(Sema &S,
+                                    const FunctionProtoType *CallOpProto) {
+  CallingConv DefaultFree = S.Context.getDefaultCallingConvention(
+      CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
+  CallingConv DefaultMember = S.Context.getDefaultCallingConvention(
+      CallOpProto->isVariadic(), /*IsCXXMethod=*/true);
+  CallingConv CallOpCC = CallOpProto->getCallConv();
+
+  // If the call-operator hasn't been changed, return both the 'free' and
+  // 'member' function calling convention.
+  if (CallOpCC == DefaultMember && DefaultMember != DefaultFree)
+    return {DefaultFree, DefaultMember};
+  return {CallOpCC};
+}
+
 QualType Sema::getLambdaConversionFunctionResultType(
-    const FunctionProtoType *CallOpProto) {
-  // The function type inside the pointer type is the same as the call
-  // operator with some tweaks. The calling convention is the default free
-  // function convention, and the type qualifications are lost.
+    const FunctionProtoType *CallOpProto, CallingConv CC) {
   const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
       CallOpProto->getExtProtoInfo();
   FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
-  CallingConv CC = Context.getDefaultCallingConvention(
-      CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
   InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
   InvokerExtInfo.TypeQuals = Qualifiers();
   assert(InvokerExtInfo.RefQualifier == RQ_None &&
-      "Lambda's call operator should not have a reference qualifier");
+         "Lambda's call operator should not have a reference qualifier");
   return Context.getFunctionType(CallOpProto->getReturnType(),
                                  CallOpProto->getParamTypes(), InvokerExtInfo);
 }
 
 /// Add a lambda's conversion to function pointer, as described in
 /// C++11 [expr.prim.lambda]p6.
-static void addFunctionPointerConversion(Sema &S,
-                                         SourceRange IntroducerRange,
+static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
                                          CXXRecordDecl *Class,
-                                         CXXMethodDecl *CallOperator) {
+                                         CXXMethodDecl *CallOperator,
+                                         QualType InvokerFunctionTy) {
   // This conversion is explicitly disabled if the lambda's function has
   // pass_object_size attributes on any of its parameters.
   auto HasPassObjectSizeAttr = [](const ParmVarDecl *P) {
@@ -1296,8 +1307,6 @@
     return;
 
   // Add the conversion to function pointer.
-  QualType InvokerFunctionTy = S.getLambdaConversionFunctionResultType(
-      CallOperator->getType()->castAs<FunctionProtoType>());
   QualType PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
 
   // Create the type of the conversion function.
@@ -1442,13 +1451,38 @@
     Class->addDecl(Invoke);
 }
 
+/// Add a lambda's conversion to function pointers, as described in
+/// C++11 [expr.prim.lambda]p6. Note that in most cases, this should emit only a
+/// single pointer conversion. In the event that the default calling convention
+/// for free and member functions is different, it will emit both conventions.
+/// FIXME: Implement emitting a version of the operator for EVERY calling
+/// convention for MSVC, as described here:
+/// https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623.
+static void addFunctionPointerConversions(Sema &S, SourceRange IntroducerRange,
+                                          CXXRecordDecl *Class,
+                                          CXXMethodDecl *CallOperator) {
+  const FunctionProtoType *CallOpProto =
+      CallOperator->getType()->castAs<FunctionProtoType>();
+  llvm::SmallVector<CallingConv, 2> Conventions =
+      getLambdaConversionFunctionCallConv(S, CallOpProto);
+
+  for (CallingConv CC : Conventions) {
+    QualType InvokerFunctionTy =
+        S.getLambdaConversionFunctionResultType(CallOpProto, CC);
+    addFunctionPointerConversion(S, IntroducerRange, Class, CallOperator,
+                                 InvokerFunctionTy);
+  }
+}
+
 /// Add a lambda's conversion to block pointer.
 static void addBlockPointerConversion(Sema &S,
                                       SourceRange IntroducerRange,
                                       CXXRecordDecl *Class,
                                       CXXMethodDecl *CallOperator) {
+  const FunctionProtoType *CallOpProto =
+      CallOperator->getType()->castAs<FunctionProtoType>();
   QualType FunctionTy = S.getLambdaConversionFunctionResultType(
-      CallOperator->getType()->castAs<FunctionProtoType>());
+      CallOpProto, getLambdaConversionFunctionCallConv(S, CallOpProto)[0]);
   QualType BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
 
   FunctionProtoType::ExtProtoInfo ConversionEPI(
@@ -1795,8 +1829,8 @@
     //   to pointer to function having the same parameter and return
     //   types as the closure type's function call operator.
     if (Captures.empty() && CaptureDefault == LCD_None)
-      addFunctionPointerConversion(*this, IntroducerRange, Class,
-                                   CallOperator);
+      addFunctionPointerConversions(*this, IntroducerRange, Class,
+                                    CallOperator);
 
     // Objective-C++:
     //   The closure type for a lambda-expression has a public non-virtual
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -14800,9 +14800,13 @@
   SynthesizedFunctionScope Scope(*this, Conv);
   assert(!Conv->getReturnType()->isUndeducedType());
 
+  QualType ConvRT = Conv->getType()->getAs<FunctionType>()->getReturnType();
+  CallingConv CC =
+      ConvRT->getPointeeType()->getAs<FunctionType>()->getCallConv();
+
   CXXRecordDecl *Lambda = Conv->getParent();
   FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
-  FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker();
+  FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC);
 
   if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
     CallOp = InstantiateFunctionDeclaration(
Index: clang/lib/AST/MicrosoftMangle.cpp
===================================================================
--- clang/lib/AST/MicrosoftMangle.cpp
+++ clang/lib/AST/MicrosoftMangle.cpp
@@ -2252,10 +2252,20 @@
       return;
     }
     Out << '@';
+  } else if (IsInLambda && D && isa<CXXConversionDecl>(D)) {
+    // The only lambda conversion operators are to function pointers, which
+    // can differ by their calling convention and are typically deduced.  So
+    // we make sure that this type gets mangled properly.
+    mangleType(T->getReturnType(), Range, QMM_Result);
   } else {
     QualType ResultType = T->getReturnType();
-    if (const auto *AT =
-            dyn_cast_or_null<AutoType>(ResultType->getContainedAutoType())) {
+    if (IsInLambda && isa<CXXConversionDecl>(D)) {
+      // The only lambda conversion operators are to function pointers, which
+      // can differ by their calling convention and are typically deduced.  So
+      // we make sure that this type gets mangled properly.
+      mangleType(ResultType, Range, QMM_Result);
+    } else if (const auto *AT = dyn_cast_or_null<AutoType>(
+                   ResultType->getContainedAutoType())) {
       Out << '?';
       mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
       Out << '?';
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -1475,6 +1475,12 @@
       return false;
   return true;
 }
+static bool allLookupResultsAreTheSame(ArrayRef<NamedDecl *> R) {
+  for (auto *D : R)
+    if (!declaresSameEntity(D, R.front()))
+      return false;
+  return true;
+}
 #endif
 
 static NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
@@ -1507,18 +1513,61 @@
 }
 
 CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
-  if (!isLambda()) return nullptr;
+  CXXMethodDecl *CallOp = getLambdaCallOperator();
+  CallingConv CC = CallOp->getType()->getAs<FunctionType>()->getCallConv();
+  return getLambdaStaticInvoker(CC);
+}
+
+static DeclContext::lookup_result
+getLambdaStaticInvokers(const CXXRecordDecl &RD) {
+  assert(RD.isLambda() && "Must be a lambda");
   DeclarationName Name =
-    &getASTContext().Idents.get(getLambdaStaticInvokerName());
-  DeclContext::lookup_result Invoker = lookup(Name);
+      &RD.getASTContext().Idents.get(getLambdaStaticInvokerName());
+  return RD.lookup(Name);
+}
+
+static CXXMethodDecl *getInvokerAsMethod(NamedDecl *ND) {
+  if (const auto *InvokerTemplate = dyn_cast<FunctionTemplateDecl>(ND))
+    return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+  return cast<CXXMethodDecl>(ND);
+}
+
+CXXMethodDecl *CXXRecordDecl::getLambdaStaticInvoker(CallingConv CC) const {
+  if (!isLambda())
+    return nullptr;
+  DeclContext::lookup_result Invoker = getLambdaStaticInvokers(*this);
   if (Invoker.empty()) return nullptr;
-  assert(allLookupResultsAreTheSame(Invoker) &&
+
+  // There might be multiple invokers in the case where we allow conversions to
+  // multiple calling conventions, filter down to just the ones we care about.
+  llvm::SmallVector<NamedDecl *, 4> FilteredInvokers;
+  std::copy_if(Invoker.begin(), Invoker.end(),
+               std::back_inserter(FilteredInvokers), [CC](NamedDecl *D) {
+                 const FunctionType *FTy = cast<ValueDecl>(D->getAsFunction())
+                                               ->getType()
+                                               ->getAs<FunctionType>();
+                 return FTy->getCallConv() == CC;
+               });
+
+  assert(allLookupResultsAreTheSame(FilteredInvokers) &&
          "More than one static invoker operator!");
-  NamedDecl *InvokerFun = Invoker.front();
-  if (const auto *InvokerTemplate = dyn_cast<FunctionTemplateDecl>(InvokerFun))
-    return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+  return getInvokerAsMethod(FilteredInvokers.front());
+}
+
+bool CXXRecordDecl::isLambdaStaticInvoker(const CXXMethodDecl *MD) const {
+  if (!this->isLambda())
+    return false;
+  DeclContext::lookup_result Invokers = getLambdaStaticInvokers(*this);
+  if (llvm::find(Invokers, MD) != Invokers.end())
+    return true;
 
-  return cast<CXXMethodDecl>(InvokerFun);
+  if (isGenericLambda() && MD->isFunctionTemplateSpecialization()) {
+    auto MDEqual = [MD = MD->getPrimaryTemplate()->getTemplatedDecl()](
+                       NamedDecl *ND) { return getInvokerAsMethod(ND) == MD; };
+    return llvm::find_if(Invokers, MDEqual) != Invokers.end();
+  }
+
+  return false;
 }
 
 void CXXRecordDecl::getCaptureFields(
@@ -2459,14 +2508,7 @@
 
 bool CXXMethodDecl::isLambdaStaticInvoker() const {
   const CXXRecordDecl *P = getParent();
-  if (P->isLambda()) {
-    if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
-      if (StaticInvoker == this) return true;
-      if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
-        return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
-    }
-  }
-  return false;
+  return P->isLambdaStaticInvoker(this);
 }
 
 CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6461,7 +6461,8 @@
   /// Get the return type to use for a lambda's conversion function(s) to
   /// function pointer type, given the type of the call operator.
   QualType
-  getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType);
+  getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType,
+                                        CallingConv CC);
 
   /// Define the "body" of the conversion from a lambda object to a
   /// function pointer.
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -1010,6 +1010,11 @@
   /// is returned by the conversion operator, and the body of which
   /// is forwarded to the lambda call operator.
   CXXMethodDecl *getLambdaStaticInvoker() const;
+  CXXMethodDecl *getLambdaStaticInvoker(CallingConv CC) const;
+
+  /// Determine whether the passed CXXMethodDecl is a lambda static invoker for
+  /// this lambda.
+  bool isLambdaStaticInvoker(const CXXMethodDecl *MD) const;
 
   /// Retrieve the generic lambda's template parameter list.
   /// Returns null if the class does not represent a lambda or a generic
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to