diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1f235b206..d310abfe4d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1920,6 +1920,19 @@ static bool canRedefineFunction(const FunctionDecl *FD, FD->getStorageClass() == SC_Extern); } +/// Is the given calling convention the ABI default for the given +/// declaration? +static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) { + CallingConv ABIDefaultCC; + if (isa(D) && cast(D)->isInstance()) { + ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic()); + } else { + // Free C function or a static method. + ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C); + } + return ABIDefaultCC == CC; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -1988,6 +2001,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // later declared or defined without one, the second decl assumes the // calling convention of the first. // + // It's OK if a function is first declared without a calling convention, + // but is later declared or defined with the default calling convention. + // // For the new decl, we have to look at the NON-canonical type to tell the // difference between a function that really doesn't have a calling // convention and one that is declared cdecl. That's because in @@ -2001,10 +2017,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; - if (OldTypeInfo.getCC() != CC_Default && - NewTypeInfo.getCC() == CC_Default) { + if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) { + // Fast path: nothing to do. + + // Inherit the CC from the previous declaration if it was specified + // there but not here. + } else if (NewTypeInfo.getCC() == CC_Default) { NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; + + // Don't complain about mismatches when the default CC is + // effectively the same as the explict one. + } else if (OldTypeInfo.getCC() == CC_Default && + isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) { + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; + } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. diff --git a/test/CodeGenCXX/microsoft-abi-default-cc.cpp b/test/CodeGenCXX/microsoft-abi-default-cc.cpp new file mode 100644 index 0000000000..d0d25ce5ef --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck -check-prefix GCABI %s +// RUN: %clang_cc1 -emit-llvm %s -o - -DMS_ABI -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck -check-prefix MSABI %s + +#ifdef MS_ABI +# define METHOD_CC __thiscall +#else +# define METHOD_CC __attribute__ ((cdecl)) +#endif + +// Test that it's OK to have multiple function declarations with the default CC +// both mentioned explicitly and implied. +void foo(); +void __cdecl foo(); +void __cdecl foo() {} +// GCABI: define void @_Z3foov() +// MSABI: define void @"\01?foo@@YAXXZ" + +void __cdecl bar(); +void bar(); +void bar() {} +// GCABI: define void @_Z3barv() +// MSABI: define void @"\01?bar@@YAXXZ" + +// Test that it's OK to mark either the method declaration or method definition +// with a default CC explicitly. +class A { +public: + void baz(); + void METHOD_CC qux(); + + void static_baz(); + void __cdecl static_qux(); +}; + +void METHOD_CC A::baz() {} +// GCABI: define void @_ZN1A3bazEv +// MSABI: define x86_thiscallcc void @"\01?baz@A@@QAEXXZ" +void A::qux() {} +// GCABI: define void @_ZN1A3quxEv +// MSABI: define x86_thiscallcc void @"\01?qux@A@@QAEXXZ" + +void __cdecl static_baz() {} +// GCABI: define void @_Z10static_bazv +// MSABI: define void @"\01?static_baz@@YAXXZ" +void static_qux() {} +// GCABI: define void @_Z10static_quxv +// MSABI: define void @"\01?static_qux@@YAXXZ"