]> granicus.if.org Git - clang/commitdiff
Tighten diagnostics for calling conventions on variadic functions
authorHans Wennborg <hans@hanshq.net>
Wed, 9 Oct 2013 18:10:25 +0000 (18:10 +0000)
committerHans Wennborg <hans@hanshq.net>
Wed, 9 Oct 2013 18:10:25 +0000 (18:10 +0000)
Follow-up from r192240.

This makes it an error to use callee-cleanup conventions on variadic
functions, except for __fastcall and __stdcall, which we ignore with
a warning for GCC and MSVC compatibility.

Differential Revision: http://llvm-reviews.chandlerc.com/D1870

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192308 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Specifiers.h
lib/Sema/SemaType.cpp
test/CodeGen/microsoft-call-conv.c
test/Sema/callingconv.c
test/Sema/mrtd.c
test/SemaCXX/calling-conv-compat.cpp

index b5e258bad4aa8b49360e5f40ffd195d76af30187..0b8093969ae3b856e96fccb63df992103bc94bad 100644 (file)
@@ -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).
index 13cb15dca43c31bf3663a61364b89c21306437f2..b4915c01c132ca50d600b71e10f602c40618ece3 100644 (file)
@@ -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;
index 18074243aa9b352544c9ec99281c17594d6b4c69..b80c58dfd1f21dec67e7027269cd26b7b6919ef5 100644 (file)
@@ -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({{.*}})
index 732c6add6ea9f063cb71a85d7091c4a17f4399aa..500c0fbfb275f3f834e303a51825d22614c7a8ea 100644 (file)
@@ -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() {}
 
index 653413b01277f9b6e7bf191fa48e49ac09e03182..ba1720e8d7dc4a61e2f4d39f2cab05cc584ec23f 100644 (file)
@@ -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, ...);
index b6cc42973c80ec8878646723dcc0accaa13e9331..2d52386add16ce3370cd55c6412d7c5735860da4 100644 (file)
@@ -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 {