diff options
author | Saleem Abdulrasool <compnerd@compnerd.org> | 2014-07-22 02:01:04 +0000 |
---|---|---|
committer | Saleem Abdulrasool <compnerd@compnerd.org> | 2014-07-22 02:01:04 +0000 |
commit | 202aac174abaaab0fcd1616f4728d11111441efa (patch) | |
tree | 3cb20c4e866e0a443f93123709b2a883942538ab /clang/lib/Sema/SemaChecking.cpp | |
parent | b4b3578af7d013f5fe4f4bb323bc52bc2991ae33 (diff) | |
download | bcm5719-llvm-202aac174abaaab0fcd1616f4728d11111441efa.tar.gz bcm5719-llvm-202aac174abaaab0fcd1616f4728d11111441efa.zip |
Sema: correct handling for __va_start for WoA
Windows ARM indicates __va_start as a variadic function. However, the function
itself is treated as having 4 formal arguments:
- (out) pointer to the va_list
- (in) address of the last named argument
- (in) slot size for the type of the last argument
- address of the last named argument
The last argument does not seem to have any bearing on codegen, and thus is not
explicitly type checked at this point.
Unlike the previous handling for __va_start, it does not currently validate if
the parameter is the last named parameter (it seems that MSVC currently accepts
this).
llvm-svn: 213595
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index f6bb8370d53..66be962fcf3 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/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) { |