Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -11169,6 +11169,17 @@ } } +static bool isDefaultCDecl(FunctionDecl *FD, Sema &S) { + // Default calling convention for MinGW is __cdecl + const llvm::Triple &T = S.Context.getTargetInfo().getTriple(); + if (T.isWindowsGNUEnvironment()) + return true; + + return llvm::StringSwitch(FD->getName()) + .Cases("main", "wmain", true) + .Default(false); +} + void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); @@ -11183,6 +11194,23 @@ if (FD->getName() != "DllMain") FD->setHasImplicitReturnZero(true); + // Explicity specified calling conventions are applied to MSVC entry points + if (!hasExplicitCallingConv(T)) { + if (isDefaultCDecl(FD, *this)) { + if (FT->getCallConv() != CC_C) { + FT = Context.adjustFunctionType(FT, + FT->getExtInfo().withCallingConv(CC_C)); + FD->setType(QualType(FT, 0)); + } + } else if (FT->getCallConv() != CC_X86StdCall) { + // Default calling convention for WinMain, wWinMain and DllMain is + // __stdcall + FT = Context.adjustFunctionType( + FT, FT->getExtInfo().withCallingConv(CC_X86StdCall)); + FD->setType(QualType(FT, 0)); + } + } + if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); Index: clang/test/CodeGenCXX/default_calling_conv.cpp =================================================================== --- clang/test/CodeGenCXX/default_calling_conv.cpp +++ clang/test/CodeGenCXX/default_calling_conv.cpp @@ -4,6 +4,8 @@ // RUN: %clang_cc1 -triple i486-unknown-linux-gnu -mrtd -emit-llvm -o - %s | FileCheck %s --check-prefix=STDCALL --check-prefix=ALL // RUN: %clang_cc1 -triple i986-unknown-linux-gnu -fdefault-calling-conv=vectorcall -emit-llvm -o - %s | FileCheck %s --check-prefix=VECTORCALL --check-prefix=ALL // RUN: %clang_cc1 -triple i986-unknown-linux-gnu -fdefault-calling-conv=regcall -emit-llvm -o - %s | FileCheck %s --check-prefix=REGCALL --check-prefix=ALL +// RUN: %clang_cc1 -triple i386-pc-win32 -target-feature +sse4.2 -fdefault-calling-conv=fastcall -emit-llvm -o - %s -DWINDOWS | FileCheck %s --check-prefix=WINDOWS +// RUN: %clang_cc1 -triple i386-pc-win32 -target-feature +sse4.2 -emit-llvm -o - %s -DEXPLICITCC | FileCheck %s --check-prefix=EXPLICITCC // CDECL: define{{.*}} void @_Z5test1v // FASTCALL: define{{.*}} x86_fastcallcc void @_Z5test1v @@ -50,3 +52,41 @@ int main() { return 1; } + +#ifdef WINDOWS +// WINDOWS: define dso_local i32 @wmain +int wmain() { + return 1; +} +// WINDOWS: define dso_local x86_stdcallcc i32 @WinMain +int WinMain() { + return 1; +} +// WINDOWS: define dso_local x86_stdcallcc i32 @wWinMain +int wWinMain() { + return 1; +} +// WINDOWS: define dso_local x86_stdcallcc i32 @DllMain +int DllMain() { + return 1; +} +#endif // Windows + +#ifdef EXPLICITCC +// EXPLICITCC: define dso_local x86_fastcallcc i32 @wmain +int __fastcall wmain() { + return 1; +} +// EXPLICITCC: define dso_local x86_fastcallcc i32 @WinMain +int __fastcall WinMain() { + return 1; +} +// EXPLICITCC: define dso_local x86_fastcallcc i32 @wWinMain +int __fastcall wWinMain() { + return 1; +} +// EXPLICITCC: define dso_local x86_fastcallcc i32 @DllMain +int __fastcall DllMain() { + return 1; +} +#endif // ExplicitCC