diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 67 | ||||
-rw-r--r-- | test/SemaCXX/microsoft-varargs-diagnostics.cpp | 42 | ||||
-rw-r--r-- | test/SemaCXX/microsoft-varargs.cpp | 22 |
4 files changed, 131 insertions, 1 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8dba089924..e254afdbad 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8281,6 +8281,7 @@ private: bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); + bool SemaBuiltinVAStartARM(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f6bb8370d5..66be962fcf 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -142,10 +142,23 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: - case Builtin::BI__va_start: if (SemaBuiltinVAStart(TheCall)) return ExprError(); break; + case Builtin::BI__va_start: { + switch (Context.getTargetInfo().getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (SemaBuiltinVAStartARM(TheCall)) + return ExprError(); + break; + default: + if (SemaBuiltinVAStart(TheCall)) + return ExprError(); + break; + } + break; + } case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -1739,6 +1752,58 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { return false; } +bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { + // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, + // const char *named_addr); + + Expr *Func = Call->getCallee(); + + if (Call->getNumArgs() < 3) + return Diag(Call->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 3 << Call->getNumArgs(); + + // Determine whether the current function is variadic or not. + bool IsVariadic; + if (BlockScopeInfo *CurBlock = getCurBlock()) + IsVariadic = CurBlock->TheDecl->isVariadic(); + else if (FunctionDecl *FD = getCurFunctionDecl()) + IsVariadic = FD->isVariadic(); + else if (ObjCMethodDecl *MD = getCurMethodDecl()) + IsVariadic = MD->isVariadic(); + else + llvm_unreachable("unexpected statement type"); + + if (!IsVariadic) { + Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + return true; + } + + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, Call, 0)) + return true; + + static const struct { + unsigned ArgNo; + QualType Type; + } ArgumentTypes[] = { + { 1, Context.getPointerType(Context.CharTy.withConst()) }, + { 2, Context.getSizeType() }, + }; + + for (const auto &AT : ArgumentTypes) { + const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens(); + if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType()) + continue; + Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg->getType() << AT.Type << 1 /* different class */ + << 0 /* qualifier difference */ << 3 /* parameter mismatch */ + << AT.ArgNo + 1 << Arg->getType() << AT.Type; + } + + return false; +} + /// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { diff --git a/test/SemaCXX/microsoft-varargs-diagnostics.cpp b/test/SemaCXX/microsoft-varargs-diagnostics.cpp new file mode 100644 index 0000000000..0b76fdd92d --- /dev/null +++ b/test/SemaCXX/microsoft-varargs-diagnostics.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only %s -verify + +extern "C" { +typedef char * va_list; +} + +void test_no_arguments(int i, ...) { + __va_start(); // expected-error{{too few arguments to function call, expected at least 3, have 0}} +} + +void test_one_argument(int i, ...) { + va_list ap; + __va_start(&ap); // expected-error{{too few arguments to function call, expected at least 3, have 1}} +} + +void test_two_arguments(int i, ...) { + va_list ap; + __va_start(&ap, &i); // expected-error{{too few arguments to function call, expected at least 3, have 2}} +} + +void test_non_last_argument(int i, int j, ...) { + va_list ap; + __va_start(&ap, &i, 4); + // expected-error@-1{{passing 'int *' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int *' vs 'const char *')}} + // expected-error@-2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}} +} + +void test_stack_allocated(int i, ...) { + va_list ap; + int j; + __va_start(&ap, &j, 4); + // expected-error@-1{{passing 'int *' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int *' vs 'const char *')}} + // expected-error@-2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}} +} + +void test_non_pointer_addressof(int i, ...) { + va_list ap; + __va_start(&ap, 1, 4); + // expected-error@-1{{passing 'int' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int' vs 'const char *')}} + // expected-error@-2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}} +} + diff --git a/test/SemaCXX/microsoft-varargs.cpp b/test/SemaCXX/microsoft-varargs.cpp new file mode 100644 index 0000000000..35f31a97c4 --- /dev/null +++ b/test/SemaCXX/microsoft-varargs.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only %s -verify +// expected-no-diagnostics + +extern "C" { +typedef char * va_list; +void __va_start(va_list *, ...); +} + +int test___va_start(int i, ...) { + va_list ap; + __va_start(&ap, ( &reinterpret_cast<const char &>(i) ), + ( (sizeof(i) + 4 - 1) & ~(4 - 1) ), + ( &reinterpret_cast<const char &>(i) )); + return (*(int *)((ap += ( (sizeof(int) + 4 - 1) & ~(4 - 1) ) + ( ((va_list)0 - (ap)) & (__alignof(int) - 1) )) - ( (sizeof(int) + 4 - 1) & ~(4 - 1) ))); +} + +int builtin(int i, ...) { + __builtin_va_list ap; + __builtin_va_start(ap, i); + return __builtin_va_arg(ap, int); +} + |