erichkeane updated this revision to Diff 298666.
erichkeane marked an inline comment as done.
erichkeane added a comment.

Calc->get.


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

https://reviews.llvm.org/D89559

Files:
  clang/lib/Sema/SemaLambda.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,79 @@
+// 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)) {};
+
+// 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
+
+#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
+  // expected-error-re@+2 {{no viable conversion from {{.*}} to 'void (*)(int, float, double) __attribute__((thiscall))}}
+  // expected-note@#3 {{candidate function}}
+  void (*__attribute__((thiscall)) thiscall_ptr2)(int, float, double) = thiscall;
+#endif // WIN32
+#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;
+
+}
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1263,20 +1263,36 @@
   PopFunctionScopeInfo();
 }
 
+static CallingConv
+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, convert the return-type to the
+  // 'free' function calling convention.
+  if (CallOpCC == DefaultMember)
+    return DefaultFree;
+  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.
+  // operator with some tweaks. The calling convention should match the call
+  // operator if it has been manually altered, and match the default free
+  // function convention if not.  Type qualifications are lost.
   const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
       CallOpProto->getExtProtoInfo();
   FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
-  CallingConv CC = Context.getDefaultCallingConvention(
-      CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
+  CallingConv CC = getLambdaConversionFunctionCallConv(*this, CallOpProto);
   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);
 }
@@ -1296,8 +1312,10 @@
     return;
 
   // Add the conversion to function pointer.
-  QualType InvokerFunctionTy = S.getLambdaConversionFunctionResultType(
-      CallOperator->getType()->castAs<FunctionProtoType>());
+  const FunctionProtoType *CallOpProto =
+      CallOperator->getType()->castAs<FunctionProtoType>();
+  QualType InvokerFunctionTy =
+      S.getLambdaConversionFunctionResultType(CallOpProto);
   QualType PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
 
   // Create the type of the conversion function.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to