erichkeane created this revision. erichkeane added reviewers: rsmith, rjmccall. erichkeane requested review of this revision.
As mentioned in the defect, the lambda static invoker does not follow the calling convention of the lambda itself, which seems wrong. This patch ensures that the calling convention of operator() is passed onto the invoker and conversion-operator type. This is accomplished by extracting the calling-convention determination code out into a separate function in order to better reflect the 'thiscall' work, as well as somewhat better support the future implementation of https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623 Repository: rC Clang 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 +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<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