diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11173,6 +11173,25 @@ } } +static bool isDefaultStdCall(FunctionDecl *FD, Sema &S) { + + // Default calling convention for main and wmain is __cdecl + if (FD->getName() == "main" || FD->getName() == "wmain") + return false; + + // Default calling convention for MinGW is __cdecl + const llvm::Triple &T = S.Context.getTargetInfo().getTriple(); + if (T.isWindowsGNUEnvironment()) + return false; + + // Default calling convention for WinMain, wWinMain and DllMain + // is __stdcall on 32 bit Windows + if (T.isOSWindows() && T.getArch() == llvm::Triple::x86) + return true; + + return false; +} + void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); @@ -11187,6 +11206,21 @@ if (FD->getName() != "DllMain") FD->setHasImplicitReturnZero(true); + // Explicity specified calling conventions are applied to MSVC entry points + if (!hasExplicitCallingConv(T)) { + if (isDefaultStdCall(FD, *this)) { + if (FT->getCallConv() != CC_X86StdCall) { + FT = Context.adjustFunctionType( + FT, FT->getExtInfo().withCallingConv(CC_X86StdCall)); + FD->setType(QualType(FT, 0)); + } + } else if (FT->getCallConv() != CC_C) { + FT = Context.adjustFunctionType(FT, + FT->getExtInfo().withCallingConv(CC_C)); + FD->setType(QualType(FT, 0)); + } + } + if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); diff --git a/clang/test/CodeGenCXX/default_calling_conv.cpp b/clang/test/CodeGenCXX/default_calling_conv.cpp --- a/clang/test/CodeGenCXX/default_calling_conv.cpp +++ b/clang/test/CodeGenCXX/default_calling_conv.cpp @@ -4,6 +4,9 @@ // 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 i686-pc-win32 -fdefault-calling-conv=vectorcall -emit-llvm -o - %s -DWINDOWS | FileCheck %s --check-prefix=WIN32 +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fdefault-calling-conv=vectorcall -emit-llvm -o - %s -DWINDOWS | FileCheck %s --check-prefix=WIN64 +// RUN: %clang_cc1 -triple i686-pc-win32 -emit-llvm -o - %s -DEXPLICITCC | FileCheck %s --check-prefix=EXPLICITCC // CDECL: define{{.*}} void @_Z5test1v // FASTCALL: define{{.*}} x86_fastcallcc void @_Z5test1v @@ -50,3 +53,45 @@ int main() { return 1; } + +#ifdef WINDOWS +// WIN32: define dso_local i32 @wmain +// WIN64: define dso_local i32 @wmain +int wmain() { + return 1; +} +// WIN32: define dso_local x86_stdcallcc i32 @WinMain +// WIN64: define dso_local i32 @WinMain +int WinMain() { + return 1; +} +// WIN32: define dso_local x86_stdcallcc i32 @wWinMain +// WIN64: define dso_local i32 @wWinMain +int wWinMain() { + return 1; +} +// WIN32: define dso_local x86_stdcallcc i32 @DllMain +// WIN64: define dso_local 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