From 479475dc593b26ad9480b4c13a767d0d7a62ac30 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 9 Jul 2019 23:17:43 +0000 Subject: [PATCH] [MS] Treat ignored explicit calling conventions as an explicit __cdecl The CCCR_Ignore action is only used for Microsoft calling conventions, mainly because MSVC does not warn when a calling convention would be ignored by the current target. This behavior is actually somewhat important, since windows.h uses WINAPI (which expands to __stdcall) widely. This distinction didn't matter much before the introduction of __vectorcall to x64 and the ability to make that the default calling convention with /Gv. Now, we can't just ignore __stdcall for x64, we have to treat it as an explicit __cdecl annotation. Fixes PR42531 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@365579 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclAttr.cpp | 22 +++++++++++--- test/CodeGen/calling-conv-ignored.c | 45 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 test/CodeGen/calling-conv-ignored.c diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e4e6a19dba..802ca52371 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -4655,10 +4655,22 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, } else { A = TI.checkCallingConvention(CC); } - if (A != TargetInfo::CCCR_OK) { - if (A == TargetInfo::CCCR_Warning) - Diag(Attrs.getLoc(), diag::warn_cconv_ignored) - << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; + + switch (A) { + case TargetInfo::CCCR_OK: + break; + + case TargetInfo::CCCR_Ignore: + // Treat an ignored convention as if it was an explicit C calling convention + // attribute. For example, __stdcall on Win x64 functions as __cdecl, so + // that command line flags that change the default convention to + // __vectorcall don't affect declarations marked __stdcall. + CC = CC_C; + break; + + case TargetInfo::CCCR_Warning: { + Diag(Attrs.getLoc(), diag::warn_cconv_ignored) + << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; // This convention is not valid for the target. Use the default function or // method calling convention. @@ -4668,6 +4680,8 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, IsVariadic = FD->isVariadic(); } CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod); + break; + } } Attrs.setProcessingCache((unsigned) CC); diff --git a/test/CodeGen/calling-conv-ignored.c b/test/CodeGen/calling-conv-ignored.c new file mode 100644 index 0000000000..e49d4c4b0d --- /dev/null +++ b/test/CodeGen/calling-conv-ignored.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -o - %s | FileCheck %s --check-prefix=X86 +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s | FileCheck %s --check-prefix=X64 +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -o - %s -fdefault-calling-conv=vectorcall | FileCheck %s --check-prefix=X86-VEC +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s -fdefault-calling-conv=vectorcall | FileCheck %s --check-prefix=X64-VEC + +void foo_default(const char *lpString1, const char *lpString2); +void __stdcall foo_std(const char *lpString1, const char *lpString2); +void __fastcall foo_fast(const char *lpString1, const char *lpString2); +void __vectorcall foo_vector(const char *lpString1, const char *lpString2); + +void __cdecl bar() { + foo_default(0, 0); + foo_std(0, 0); + foo_fast(0, 0); + foo_vector(0, 0); +} + +// X86-LABEL: define dso_local void @bar() +// X86: call void @foo_default(i8* null, i8* null) +// X86: call x86_stdcallcc void @"\01_foo_std@8"(i8* null, i8* null) +// X86: call x86_fastcallcc void @"\01@foo_fast@8"(i8* inreg null, i8* inreg null) +// X86: call x86_vectorcallcc void @"\01foo_vector@@8"(i8* inreg null, i8* inreg null) +// X86: ret void + +// X64-LABEL: define dso_local void @bar() +// X64: call void @foo_default(i8* null, i8* null) +// X64: call void @foo_std(i8* null, i8* null) +// X64: call void @foo_fast(i8* null, i8* null) +// X64: call x86_vectorcallcc void @"\01foo_vector@@16"(i8* null, i8* null) +// X64: ret void + +// X86-VEC-LABEL: define dso_local void @bar() +// X86-VEC: call x86_vectorcallcc void @"\01foo_default@@8"(i8* inreg null, i8* inreg null) +// X86-VEC: call x86_stdcallcc void @"\01_foo_std@8"(i8* null, i8* null) +// X86-VEC: call x86_fastcallcc void @"\01@foo_fast@8"(i8* inreg null, i8* inreg null) +// X86-VEC: call x86_vectorcallcc void @"\01foo_vector@@8"(i8* inreg null, i8* inreg null) +// X86-VEC: ret void + +// X64-VEC-LABEL: define dso_local void @bar() +// X64-VEC: call x86_vectorcallcc void @"\01foo_default@@16"(i8* null, i8* null) +// X64-VEC: call void @foo_std(i8* null, i8* null) +// X64-VEC: call void @foo_fast(i8* null, i8* null) +// X64-VEC: call x86_vectorcallcc void @"\01foo_vector@@16"(i8* null, i8* null) +// X64-VEC: ret void + -- 2.40.0