Don't trap when passing non-POD arguments to variadic functions in MS-compatibility mode

Clang warns (treated as error by default, but still ignored in system headers)
when passing non-POD arguments to variadic functions, and generates a trap
instruction to crash the program if that code is ever run.

Unfortunately, MSVC happily generates code for such calls without a warning,
and there is code in system headers that use it.

This makes Clang not insert the trap instruction when in -fms-compatibility
mode, while still generating the warning/error message.

Differential Revision: http://reviews.llvm.org/D5492

llvm-svn: 218640
This commit is contained in:
Hans Wennborg 2014-09-29 23:06:57 +00:00
parent b166d45730
commit d9dd4d29b7
5 changed files with 35 additions and 0 deletions

View File

@ -7737,6 +7737,7 @@ public:
VAK_Valid,
VAK_ValidInCXX11,
VAK_Undefined,
VAK_MSVCUndefined,
VAK_Invalid
};

View File

@ -3569,6 +3569,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
break;
case Sema::VAK_Undefined:
case Sema::VAK_MSVCUndefined:
EmitFormatDiagnostic(
S.PDiag(diag::warn_non_pod_vararg_with_format_string)
<< S.getLangOpts().CPlusPlus11

View File

@ -800,6 +800,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isObjCObjectType())
return VAK_Invalid;
if (getLangOpts().MSVCCompat)
return VAK_MSVCUndefined;
// FIXME: In C++11, these cases are conditionally-supported, meaning we're
// permitted to reject them. We should consider doing so.
return VAK_Undefined;
@ -829,6 +832,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
break;
case VAK_Undefined:
case VAK_MSVCUndefined:
DiagRuntimeBehavior(
E->getLocStart(), nullptr,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)

View File

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -Wno-error=non-pod-varargs -triple i686-pc-win32 -fms-compatibility -emit-llvm -o - %s | FileCheck %s -check-prefix=X86 -check-prefix=CHECK
// RUN: %clang_cc1 -Wno-error=non-pod-varargs -triple x86_64-pc-win32 -fms-compatibility -emit-llvm -o - %s | FileCheck %s -check-prefix=X64 -check-prefix=CHECK
struct X {
X();
~X();
int data;
};
void vararg(...);
void test(X x) {
// CHECK-LABEL: define void @"\01?test@@YAXUX@@@Z"
// X86: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.X }>
// X86: call void (<{ %struct.X }>*, ...)* bitcast (void (...)* @"\01?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca %[[argmem]])
// X64: %[[valptr:[^ ]*]] = getelementptr %struct.X* %{{[^ ]*}}, i32 0, i32 0
// X64: %[[val:[^ ]*]] = load i32* %[[valptr]]
// X64: call void (...)* @"\01?vararg@@YAXZZ"(i32 %[[val]])
// CHECK-NOT: llvm.trap
vararg(x);
// CHECK: ret void
}

View File

@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-error=non-pod-varargs
// Check that the warning is still there under -fms-compatibility.
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-error=non-pod-varargs -fms-compatibility
extern char version[];
class C {