From 5305cff6f260894fa8642805ad004847889fb2a4 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 19 Sep 2014 23:07:12 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218166 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 +++ lib/Sema/SemaDecl.cpp | 14 +++++++---- test/CodeGen/mangle-windows.c | 3 +++ test/CodeGen/mrtd.c | 7 +++++- test/Sema/decl-microsoft-call-conv.c | 28 ++++++++++++++++++---- test/Sema/stdcall-fastcall.c | 2 +- 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d567cce2d1..559bf62fd8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2236,6 +2236,9 @@ def warn_cconv_ignored : Warning< "calling convention %0 ignored for this target">, InGroup; 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>; def err_cconv_varargs : Error< "variadic function cannot use %0 calling convention">; def warn_cconv_varargs : Warning< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0aaa60c90f..535e33a2b6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7937,15 +7937,19 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // 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(NewQType); if (isa(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/test/CodeGen/mangle-windows.c b/test/CodeGen/mangle-windows.c index 37d1018283..1d97831c47 100644 --- a/test/CodeGen/mangle-windows.c +++ b/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/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c index 8fa7cf02ce..79cd490084 100644 --- a/test/CodeGen/mrtd.c +++ b/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/test/Sema/decl-microsoft-call-conv.c b/test/Sema/decl-microsoft-call-conv.c index 88a6d920a0..3ec4d5ebea 100644 --- a/test/Sema/decl-microsoft-call-conv.c +++ b/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/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c index dea1fc5e7a..90429327a7 100644 --- a/test/Sema/stdcall-fastcall.c +++ b/test/Sema/stdcall-fastcall.c @@ -6,7 +6,7 @@ int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies // 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 -- 2.40.0