Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -1263,20 +1263,36 @@ PopFunctionScopeInfo(); } +static CallingConv +calcLambdaConversionFunctionCallConv(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 = calcLambdaConversionFunctionCallConv(*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()); + const FunctionProtoType *CallOpProto = + CallOperator->getType()->castAs(); + QualType InvokerFunctionTy = + S.getLambdaConversionFunctionResultType(CallOpProto); QualType PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy); // Create the type of the conversion function. 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; + +}