Follow-up to r214408: Warn on other callee-cleanup functions without prototype too.
According to lore, we used to verifier-fail on:
void __thiscall f();
int main() { f(1); }
So that's fixed now. System headers use prototype-less __stdcall functions,
so make that a warning that's DefaultError -- then it fires on regular code
but is suppressed in system headers.
Since it's used in system headers, we have codegen tests for this; massage
them slightly so that they still compile.
llvm-svn: 218166
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d567cce..559bf62 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2236,6 +2236,9 @@
"calling convention %0 ignored for this target">, InGroup<IgnoredAttributes>;
def err_cconv_knr : Error<
"function with no prototype cannot use %0 calling convention">;
+def warn_cconv_knr : Warning<
+ "function with no prototype cannot use %0 calling convention">,
+ DefaultError, InGroup<DiagGroup<"missing-prototype-for-cc">>;
def err_cconv_varargs : Error<
"variadic function cannot use %0 calling convention">;
def warn_cconv_varargs : Warning<
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0aaa60c..535e33a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7937,15 +7937,19 @@
// Semantic checking for this function declaration (in isolation).
- // Diagnose the use of X86 fastcall on unprototyped functions.
+ // Diagnose the use of callee-cleanup calls on unprototyped functions.
QualType NewQType = Context.getCanonicalType(NewFD->getType());
const FunctionType *NewType = cast<FunctionType>(NewQType);
if (isa<FunctionNoProtoType>(NewType)) {
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
- if (NewTypeInfo.getCC() == CC_X86FastCall)
- Diag(NewFD->getLocation(), diag::err_cconv_knr)
- << FunctionType::getNameForCallConv(CC_X86FastCall);
- // TODO: Also diagnose unprototyped stdcall functions?
+ if (isCalleeCleanup(NewTypeInfo.getCC())) {
+ // Windows system headers sometimes accidentally use stdcall without
+ // (void) parameters, so use a default-error warning in this case :-/
+ int DiagID = NewTypeInfo.getCC() == CC_X86StdCall
+ ? diag::warn_cconv_knr : diag::err_cconv_knr;
+ Diag(NewFD->getLocation(), DiagID)
+ << FunctionType::getNameForCallConv(NewTypeInfo.getCC());
+ }
}
if (getLangOpts().CPlusPlus) {
diff --git a/clang/test/CodeGen/mangle-windows.c b/clang/test/CodeGen/mangle-windows.c
index 37d1018..1d97831 100644
--- a/clang/test/CodeGen/mangle-windows.c
+++ b/clang/test/CodeGen/mangle-windows.c
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | FileCheck %s
+// prototype-less __stdcall functions are only allowed in system headers.
+# 1 "fake_system_header.h" 1 3 4
+
void __stdcall f1(void) {}
// CHECK: define x86_stdcallcc void @"\01_f1@0"
diff --git a/clang/test/CodeGen/mrtd.c b/clang/test/CodeGen/mrtd.c
index 8fa7cf0..79cd490 100644
--- a/clang/test/CodeGen/mrtd.c
+++ b/clang/test/CodeGen/mrtd.c
@@ -1,4 +1,9 @@
-// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -Wsystem-headers -Wno-error=missing-prototype-for-cc -emit-llvm -o - %s 2>&1 | FileCheck %s
+
+// prototype-less __stdcall functions are only allowed in system headers.
+# 1 "fake_system_header.h" 1 3 4
+
+// CHECK: fake_system_header.h:9:3: warning: function with no prototype cannot use stdcall calling convention
void baz(int arg);
diff --git a/clang/test/Sema/decl-microsoft-call-conv.c b/clang/test/Sema/decl-microsoft-call-conv.c
index 88a6d92..3ec4d5e 100644
--- a/clang/test/Sema/decl-microsoft-call-conv.c
+++ b/clang/test/Sema/decl-microsoft-call-conv.c
@@ -2,8 +2,28 @@
// It's important that this is a .c file.
-// This is fine, as CrcGenerateTable() has a prototype.
-void __fastcall CrcGenerateTable(void);
-void __fastcall CrcGenerateTable() {}
+// This is fine, as CrcGenerateTable*() has a prototype.
+void __fastcall CrcGenerateTableFastcall(void);
+void __fastcall CrcGenerateTableFastcall() {}
+void __stdcall CrcGenerateTableStdcall(void);
+void __stdcall CrcGenerateTableStdcall() {}
+void __thiscall CrcGenerateTableThiscall(void);
+void __thiscall CrcGenerateTableThiscall() {}
+void __pascal CrcGenerateTablePascal(void);
+void __pascal CrcGenerateTablePascal() {}
-void __fastcall CrcGenerateTableNoProto() {} // expected-error{{function with no prototype cannot use fastcall calling convention}}
+void __fastcall CrcGenerateTableNoProtoFastcall() {} // expected-error{{function with no prototype cannot use fastcall calling convention}}
+void __stdcall CrcGenerateTableNoProtoStdcall() {} // expected-error{{function with no prototype cannot use stdcall calling convention}}
+void __thiscall CrcGenerateTableNoProtoThiscall() {} // expected-error{{function with no prototype cannot use thiscall calling convention}}
+void __pascal CrcGenerateTableNoProtoPascal() {} // expected-error{{function with no prototype cannot use pascal calling convention}}
+
+// Regular calling convention is fine.
+void CrcGenerateTableNoProto() {}
+
+
+// In system headers, the stdcall version should be a warning.
+# 1 "fake_system_header.h" 1 3 4
+void __fastcall SystemHeaderFastcall() {} // expected-error{{function with no prototype cannot use fastcall calling convention}}
+void __stdcall SystemHeaderStdcall() {}
+void __thiscall SystemHeaderThiscall() {} // expected-error{{function with no prototype cannot use thiscall calling convention}}
+void __pascal SystemHeaderPascal() {} // expected-error{{function with no prototype cannot use pascal calling convention}}
diff --git a/clang/test/Sema/stdcall-fastcall.c b/clang/test/Sema/stdcall-fastcall.c
index dea1fc5..9042932 100644
--- a/clang/test/Sema/stdcall-fastcall.c
+++ b/clang/test/Sema/stdcall-fastcall.c
@@ -6,7 +6,7 @@
// Different CC qualifiers are not compatible
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{fastcall and stdcall attributes are not compatible}}
-void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}}
+void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}} expected-error{{function with no prototype cannot use stdcall calling convention}}
void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}
// rdar://8876096