diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c6a00b1dad1..f8e6c9d5ee4 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1037,6 +1037,8 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { default: return false; case X86::BI__builtin_cpu_supports: return SemaBuiltinCpuSupports(TheCall); + case X86::BI__builtin_ms_va_start: + return SemaBuiltinMSVAStart(TheCall); case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break; case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -2317,9 +2319,10 @@ bool Sema::CheckObjCString(Expr *Arg) { return false; } -/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity. -/// Emit an error and return true on failure, return false on success. -bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { +/// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' +/// for validity. Emit an error and return true on failure; return false +/// on success. +bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { Expr *Fn = TheCall->getCallee(); if (TheCall->getNumArgs() > 2) { Diag(TheCall->getArg(2)->getLocStart(), @@ -2397,6 +2400,48 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { return false; } +/// Check the arguments to '__builtin_va_start' for validity, and that +/// it was called from a function of the native ABI. +/// Emit an error and return true on failure; return false on success. +bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { + // On x86-64 Unix, don't allow this in Win64 ABI functions. + // On x64 Windows, don't allow this in System V ABI functions. + // (Yes, that means there's no corresponding way to support variadic + // System V ABI functions on Windows.) + if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) { + unsigned OS = Context.getTargetInfo().getTriple().getOS(); + clang::CallingConv CC = CC_C; + if (const FunctionDecl *FD = getCurFunctionDecl()) + CC = FD->getType()->getAs<FunctionType>()->getCallConv(); + if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) || + (OS != llvm::Triple::Win32 && CC == CC_X86_64Win64)) + return Diag(TheCall->getCallee()->getLocStart(), + diag::err_va_start_used_in_wrong_abi_function) + << (OS != llvm::Triple::Win32); + } + return SemaBuiltinVAStartImpl(TheCall); +} + +/// Check the arguments to '__builtin_ms_va_start' for validity, and that +/// it was called from a Win64 ABI function. +/// Emit an error and return true on failure; return false on success. +bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) { + // This only makes sense for x86-64. + const llvm::Triple &TT = Context.getTargetInfo().getTriple(); + Expr *Callee = TheCall->getCallee(); + if (TT.getArch() != llvm::Triple::x86_64) + return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt); + // Don't allow this in System V ABI functions. + clang::CallingConv CC = CC_C; + if (const FunctionDecl *FD = getCurFunctionDecl()) + CC = FD->getType()->getAs<FunctionType>()->getCallConv(); + if (CC == CC_X86_64SysV || + (TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64)) + return Diag(Callee->getLocStart(), + diag::err_ms_va_start_used_in_sysv_function); + return SemaBuiltinVAStartImpl(TheCall); +} + bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); |

