summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/Specifiers.h13
-rw-r--r--clang/lib/Sema/SemaType.cpp28
-rw-r--r--clang/test/CodeGen/microsoft-call-conv.c7
-rw-r--r--clang/test/Sema/callingconv.c7
-rw-r--r--clang/test/Sema/mrtd.c6
-rw-r--r--clang/test/SemaCXX/calling-conv-compat.cpp2
6 files changed, 39 insertions, 24 deletions
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index b5e258bad4a..0b8093969ae 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -220,6 +220,19 @@ namespace clang {
CC_IntelOclBicc // __attribute__((intel_ocl_bicc))
};
+ /// \brief Checks whether the given calling convention is callee-cleanup.
+ inline bool isCalleeCleanup(CallingConv CC) {
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86FastCall:
+ case CC_X86ThisCall:
+ case CC_X86Pascal:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/// \brief The storage duration for an object (per C++ [basic.stc]).
enum StorageDuration {
SD_FullExpression, ///< Full-expression storage duration (for temporaries).
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 13cb15dca43..b4915c01c13 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4542,22 +4542,26 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
}
- // Diagnose the use of X86 fastcall on varargs or unprototyped functions.
- if (CC == CC_X86FastCall) {
- if (isa<FunctionNoProtoType>(fn)) {
- S.Diag(attr.getLoc(), diag::err_cconv_knr)
- << FunctionType::getNameForCallConv(CC);
+ // Diagnose use of callee-cleanup calling convention on variadic functions.
+ if (isCalleeCleanup(CC)) {
+ const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
+ if (FnP && FnP->isVariadic()) {
+ unsigned DiagID = diag::err_cconv_varargs;
+ // stdcall and fastcall are ignored with a warning for GCC and MS
+ // compatibility.
+ if (CC == CC_X86StdCall || CC == CC_X86FastCall)
+ DiagID = diag::warn_cconv_varargs;
+
+ S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC);
attr.setInvalid();
return true;
}
+ }
- const FunctionProtoType *FnP = cast<FunctionProtoType>(fn);
- if (FnP->isVariadic()) {
- // In MS compatibility mode, this is just a warning.
- const LangOptions &L = S.getLangOpts();
- unsigned DiagID = L.MicrosoftMode ? diag::warn_cconv_varargs
- : diag::err_cconv_varargs;
- S.Diag(attr.getLoc(), DiagID)
+ // Diagnose the use of X86 fastcall on unprototyped functions.
+ if (CC == CC_X86FastCall) {
+ if (isa<FunctionNoProtoType>(fn)) {
+ S.Diag(attr.getLoc(), diag::err_cconv_knr)
<< FunctionType::getNameForCallConv(CC);
attr.setInvalid();
return true;
diff --git a/clang/test/CodeGen/microsoft-call-conv.c b/clang/test/CodeGen/microsoft-call-conv.c
index 18074243aa9..b80c58dfd1f 100644
--- a/clang/test/CodeGen/microsoft-call-conv.c
+++ b/clang/test/CodeGen/microsoft-call-conv.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm < %s | FileCheck %s
-// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm -fms-compatibility -DWIN < %s | FileCheck --check-prefix=WIN %s
+// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm -mrtd < %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm -fms-compatibility < %s
void __fastcall f1(void);
void __stdcall f2(void);
@@ -51,9 +52,9 @@ void f8(void) {
}
// PR12535
-#ifdef WIN
void __fastcall f9(int x, int y) {};
// WIN: define x86_fastcallcc void @f9({{.*}})
void __fastcall f10(int x, ...) {};
// WIN: define void @f10({{.*}})
-#endif
+void __stdcall f11(int x, ...) {};
+// WIN: define void @f11({{.*}})
diff --git a/clang/test/Sema/callingconv.c b/clang/test/Sema/callingconv.c
index 732c6add6ea..500c0fbfb27 100644
--- a/clang/test/Sema/callingconv.c
+++ b/clang/test/Sema/callingconv.c
@@ -16,13 +16,12 @@ void __attribute__((fastcall)) test0() { // expected-error {{function with no pr
void __attribute__((fastcall)) test1(void) {
}
-#ifdef WIN
void __attribute__((fastcall)) test2(int a, ...) { // expected-warning {{fastcall calling convention ignored on variadic function}}
}
-#else
-void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use fastcall calling convention}}
+void __attribute__((stdcall)) test3(int a, ...) { // expected-warning {{stdcall calling convention ignored on variadic function}}
+}
+void __attribute__((thiscall)) test4(int a, ...) { // expected-error {{variadic function cannot use thiscall calling convention}}
}
-#endif
void __attribute__((cdecl)) ctest0() {}
diff --git a/clang/test/Sema/mrtd.c b/clang/test/Sema/mrtd.c
index 653413b0127..ba1720e8d7d 100644
--- a/clang/test/Sema/mrtd.c
+++ b/clang/test/Sema/mrtd.c
@@ -12,8 +12,7 @@ void __attribute__((stdcall)) nonvariadic1(int a, int b, int c);
void nonvariadic2(int a, int b, int c);
void __attribute__((stdcall)) nonvariadic2(int a, int b, int c) { }
-// expected-note@+2 {{previous declaration is here}}
-// expected-error@+2 {{function declared 'stdcall' here was previously declared without calling convention}}
+// expected-warning@+2 {{stdcall calling convention ignored on variadic function}}
void variadic(int a, ...);
void __attribute__((stdcall)) variadic(int a, ...);
@@ -34,7 +33,6 @@ __attribute__((cdecl)) extern void (*b)(int, ...);
extern void (*c)(int, int);
__attribute__((stdcall)) extern void (*c)(int, int);
-// expected-note@+2 {{previous definition is here}}
-// expected-error@+2 {{redefinition of 'd' with a different type: 'void ((*))(int, ...) __attribute__((stdcall))' vs 'void (*)(int, ...)'}}
+// expected-warning@+2 {{stdcall calling convention ignored on variadic function}}
extern void (*d)(int, ...);
__attribute__((stdcall)) extern void (*d)(int, ...);
diff --git a/clang/test/SemaCXX/calling-conv-compat.cpp b/clang/test/SemaCXX/calling-conv-compat.cpp
index b6cc42973c8..2d52386add1 100644
--- a/clang/test/SemaCXX/calling-conv-compat.cpp
+++ b/clang/test/SemaCXX/calling-conv-compat.cpp
@@ -248,7 +248,7 @@ namespace Variadic {
struct A {
void member_default(int, ...);
void __cdecl member_cdecl(int, ...);
- void __thiscall member_thiscall(int, ...);
+ void __thiscall member_thiscall(int, ...); // expected-error {{variadic function cannot use thiscall calling convention}}
};
struct B : public A {
OpenPOWER on IntegriCloud