From d8b8f544d9de30cd14584094596090d3f9992345 Mon Sep 17 00:00:00 2001 From: Elizabeth Andrews Date: Thu, 18 Mar 2021 02:58:35 -0700 Subject: [PATCH] [Reland] "Do not apply calling conventions to MSVC entry points" This patch is a second attempt at fixing a link error for MSVC entry points when calling conventions are specified using a flag. Calling conventions specified using flags should not be applied to MSVC entry points. The default calling convention is set in this case. The default calling convention for MSVC entry points main and wmain is cdecl. For WinMain, wWinMain and DllMain, the default calling convention is stdcall on 32 bit Windows. Explicitly specified calling conventions are applied to MSVC entry points. For MinGW, the default calling convention for all MSVC entry points is cdecl. First attempt: 4cff1b40dacf6 Revert of first attempt: bebfc3b92d5e8 Differential Revision: https://reviews.llvm.org/D97941 --- clang/lib/Sema/SemaDecl.cpp | 34 +++++++++++++++++++ clang/test/CodeGenCXX/default_calling_conv.cpp | 45 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b962bd9..76e3ee9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11173,6 +11173,25 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { } } +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 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { 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 index e3d7ac4..83d1200 100644 --- 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 @@ void test() { 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 -- 2.7.4