Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -2208,6 +2208,9 @@ /// redeclaration time if the decl is static. bool isStaticMember(); + /// Returns true if this declares a constructor or a destructor. + bool isCtorOrDtor(); + void setRedeclaration(bool Val) { Redeclaration = Val; } bool isRedeclaration() const { return Redeclaration; } }; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2915,7 +2915,7 @@ /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. - void adjustMemberFunctionCC(QualType &T, bool IsStatic); + void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -351,6 +351,11 @@ getName().OperatorFunctionId.Operator)); } +bool Declarator::isCtorOrDtor() { + return (getName().getKind() == UnqualifiedId::IK_ConstructorName) || + (getName().getKind() == UnqualifiedId::IK_DestructorName); +} + bool DeclSpec::hasTagDefinition() const { if (!TypeSpecOwned) return false; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -7219,7 +7219,7 @@ << DeclSpec::getSpecifierName(TSCS); if (D.isFirstDeclarationOfMember()) - adjustMemberFunctionCC(R, D.isStaticMember()); + adjustMemberFunctionCC( R, D.isStaticMember(), D.isCtorOrDtor()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -2269,8 +2269,11 @@ // Adjust the default free function calling convention to the default method // calling convention. + bool is_ctor_or_dtor = + (Entity.getNameKind() == DeclarationName::CXXConstructorName) || + (Entity.getNameKind() == DeclarationName::CXXDestructorName); if (T->isFunctionType()) - adjustMemberFunctionCC(T, /*IsStatic=*/false); + adjustMemberFunctionCC(T, /*IsStatic=*/false, is_ctor_or_dtor); return Context.getMemberPointerType(T, Class.getTypePtr()); } @@ -5842,24 +5845,35 @@ return false; } -void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) { +void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, + bool IsCtorOrDtor) { FunctionTypeUnwrapper Unwrapped(*this, T); const FunctionType *FT = Unwrapped.get(); bool IsVariadic = (isa(FT) && cast(FT)->isVariadic()); - - // Only adjust types with the default convention. For example, on Windows we - // should adjust a __cdecl type to __thiscall for instance methods, and a - // __thiscall type to __cdecl for static methods. CallingConv CurCC = FT->getCallConv(); - CallingConv FromCC = - Context.getDefaultCallingConvention(IsVariadic, IsStatic); - CallingConv ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic); - if (CurCC != FromCC || FromCC == ToCC) - return; + CallingConv ToCC; - if (hasExplicitCallingConv(T)) - return; + // MS compiler transforms __stdcall in ctors/dtors to __thiscall in 32 bit + // mode. We should do the same. + if ((CurCC == CC_X86StdCall) && IsCtorOrDtor && + (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment() && + Context.getTargetInfo().getTriple().isArch32Bit())) + ToCC = CC_X86ThisCall; + // Default adjustment. + else { + // Only adjust types with the default convention. For example, on Windows + // we should adjust a __cdecl type to __thiscall for instance methods, and a + // __thiscall type to __cdecl for static methods. + CallingConv FromCC = + Context.getDefaultCallingConvention(IsVariadic, IsStatic); + ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic); + if (CurCC != FromCC || FromCC == ToCC) + return; + + if (hasExplicitCallingConv(T)) + return; + } FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(ToCC)); QualType Wrapped = Unwrapped.wrap(*this, FT); Index: test/CodeGenCXX/microsoft-abi-structors.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-structors.cpp +++ test/CodeGenCXX/microsoft-abi-structors.cpp @@ -5,6 +5,7 @@ // RUN: FileCheck --check-prefix DTORS %s < %t // RUN: FileCheck --check-prefix DTORS2 %s < %t // RUN: FileCheck --check-prefix DTORS3 %s < %t +// RUN: FileCheck --check-prefix DTORS4 %s < %t // // RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s @@ -458,3 +459,18 @@ // CHECK: (%"struct.(anonymous namespace)::A"* %this, i32 %should_call_delete) // CHECK: define internal x86_thiscallcc void @"\01??1A@?A@@UAE@XZ" // CHECK: (%"struct.(anonymous namespace)::A"* %this) + +// Check that we correctly transform __stdcall to __thiscall for ctors and +// dtors. +class G { + public: + __stdcall G() {}; +// DTORS4: define linkonce_odr x86_thiscallcc %class.G* @"\01??0G@@QAE@XZ" + __stdcall ~G() {}; +// DTORS4: define linkonce_odr x86_thiscallcc void @"\01??1G@@QAE@XZ" +}; + +extern void testG() { + G g; +} +