From 21630d5d23e01b5eef9f6958c21dfacfce20da02 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Tue, 19 Jun 2018 14:36:04 +0000 Subject: [PATCH] Implement semantic checking for __builtin_signbit. r242675 changed the signature for the signbit builtin but did not introduce proper semantic checking to ensure the arguments are as-expected. This patch groups the signbit builtin along with the other fp classification builtins. Fixes PR28172. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@335048 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaChecking.cpp | 1625 +++++++++++++++++++------------------ test/Sema/builtins.c | 423 +++++----- 2 files changed, 1039 insertions(+), 1009 deletions(-) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 5530bd8fe7..e18dd056e9 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -772,406 +772,409 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { } // Since return type of reserve_read/write_pipe built-in function is - // reserve_id_t, which is not defined in the builtin def file , we used int - // as return type and need to override the return type of these functions. - Call->setType(S.Context.OCLReserveIDTy); - - return false; -} - -// Performs a semantic analysis on {work_group_/sub_group_ -// /_}commit_{read/write}_pipe -// \param S Reference to the semantic analyzer. -// \param Call The call to the builtin function to be analyzed. -// \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 2)) - return true; - - if (checkOpenCLPipeArg(S, Call)) - return true; - - // Check reserve_id_t. - if (!Call->getArg(1)->getType()->isReserveIDT()) { - S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.OCLReserveIDTy - << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); - return true; - } - - return false; -} - -// Performs a semantic analysis on the call to built-in Pipe -// Query Functions. -// \param S Reference to the semantic analyzer. -// \param Call The call to the builtin function to be analyzed. -// \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { - if (checkArgCount(S, Call, 1)) - return true; - - if (!Call->getArg(0)->getType()->isPipeType()) { - S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) - << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); - return true; - } - - return false; -} - -// OpenCL v2.0 s6.13.9 - Address space qualifier functions. -// Performs semantic analysis for the to_global/local/private call. -// \param S Reference to the semantic analyzer. -// \param BuiltinID ID of the builtin function. -// \param Call A pointer to the builtin call. -// \return True if a semantic error has been found, false otherwise. -static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, - CallExpr *Call) { - if (Call->getNumArgs() != 1) { - S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num) - << Call->getDirectCallee() << Call->getSourceRange(); - return true; - } - - auto RT = Call->getArg(0)->getType(); - if (!RT->isPointerType() || RT->getPointeeType() - .getAddressSpace() == LangAS::opencl_constant) { - S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg) - << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); - return true; - } - - RT = RT->getPointeeType(); - auto Qual = RT.getQualifiers(); - switch (BuiltinID) { - case Builtin::BIto_global: - Qual.setAddressSpace(LangAS::opencl_global); - break; - case Builtin::BIto_local: - Qual.setAddressSpace(LangAS::opencl_local); - break; - case Builtin::BIto_private: - Qual.setAddressSpace(LangAS::opencl_private); - break; - default: - llvm_unreachable("Invalid builtin function"); - } - Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( - RT.getUnqualifiedType(), Qual))); - - return false; -} - -// Emit an error and return true if the current architecture is not in the list -// of supported architectures. -static bool -CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, - ArrayRef SupportedArchs) { - llvm::Triple::ArchType CurArch = - S.getASTContext().getTargetInfo().getTriple().getArch(); - if (llvm::is_contained(SupportedArchs, CurArch)) - return false; - S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported) - << TheCall->getSourceRange(); - return true; -} - -ExprResult -Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, - CallExpr *TheCall) { - ExprResult TheCallResult(TheCall); - - // Find out if any arguments are required to be integer constant expressions. - unsigned ICEArguments = 0; - ASTContext::GetBuiltinTypeError Error; - Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); - if (Error != ASTContext::GE_None) - ICEArguments = 0; // Don't diagnose previously diagnosed errors. - - // If any arguments are required to be ICE's, check and diagnose. - for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { - // Skip arguments not required to be ICE's. - if ((ICEArguments & (1 << ArgNo)) == 0) continue; - - llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) - return true; - ICEArguments &= ~(1 << ArgNo); - } - - switch (BuiltinID) { - case Builtin::BI__builtin___CFStringMakeConstantString: - assert(TheCall->getNumArgs() == 1 && - "Wrong # arguments to builtin CFStringMakeConstantString"); - if (CheckObjCString(TheCall->getArg(0))) - return ExprError(); - break; - case Builtin::BI__builtin_ms_va_start: - case Builtin::BI__builtin_stdarg_start: - case Builtin::BI__builtin_va_start: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) - return ExprError(); - break; - case Builtin::BI__va_start: { - switch (Context.getTargetInfo().getTriple().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (SemaBuiltinVAStartARMMicrosoft(TheCall)) - return ExprError(); - break; - default: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) - return ExprError(); - break; - } - break; - } - - // The acquire, release, and no fence variants are ARM and AArch64 only. - case Builtin::BI_interlockedbittestandset_acq: - case Builtin::BI_interlockedbittestandset_rel: - case Builtin::BI_interlockedbittestandset_nf: - case Builtin::BI_interlockedbittestandreset_acq: - case Builtin::BI_interlockedbittestandreset_rel: - case Builtin::BI_interlockedbittestandreset_nf: - if (CheckBuiltinTargetSupport( - *this, BuiltinID, TheCall, - {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) - return ExprError(); - break; - - // The 64-bit bittest variants are x64, ARM, and AArch64 only. - case Builtin::BI_bittest64: - case Builtin::BI_bittestandcomplement64: - case Builtin::BI_bittestandreset64: - case Builtin::BI_bittestandset64: - case Builtin::BI_interlockedbittestandreset64: - case Builtin::BI_interlockedbittestandset64: - if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, - {llvm::Triple::x86_64, llvm::Triple::arm, - llvm::Triple::thumb, llvm::Triple::aarch64})) - return ExprError(); - break; - - case Builtin::BI__builtin_isgreater: - case Builtin::BI__builtin_isgreaterequal: - case Builtin::BI__builtin_isless: - case Builtin::BI__builtin_islessequal: - case Builtin::BI__builtin_islessgreater: - case Builtin::BI__builtin_isunordered: - if (SemaBuiltinUnorderedCompare(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_fpclassify: - if (SemaBuiltinFPClassification(TheCall, 6)) - return ExprError(); - break; - case Builtin::BI__builtin_isfinite: - case Builtin::BI__builtin_isinf: - case Builtin::BI__builtin_isinf_sign: - case Builtin::BI__builtin_isnan: - case Builtin::BI__builtin_isnormal: - if (SemaBuiltinFPClassification(TheCall, 1)) - return ExprError(); - break; - case Builtin::BI__builtin_shufflevector: - return SemaBuiltinShuffleVector(TheCall); - // TheCall will be freed by the smart pointer here, but that's fine, since - // SemaBuiltinShuffleVector guts it, but then doesn't release it. - case Builtin::BI__builtin_prefetch: - if (SemaBuiltinPrefetch(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_alloca_with_align: - if (SemaBuiltinAllocaWithAlign(TheCall)) - return ExprError(); - break; - case Builtin::BI__assume: - case Builtin::BI__builtin_assume: - if (SemaBuiltinAssume(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_assume_aligned: - if (SemaBuiltinAssumeAligned(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_object_size: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) - return ExprError(); - break; - case Builtin::BI__builtin_longjmp: - if (SemaBuiltinLongjmp(TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_setjmp: - if (SemaBuiltinSetjmp(TheCall)) - return ExprError(); - break; - case Builtin::BI_setjmp: - case Builtin::BI_setjmpex: - if (checkArgCount(*this, TheCall, 1)) - return true; - break; - case Builtin::BI__builtin_classify_type: - if (checkArgCount(*this, TheCall, 1)) return true; - TheCall->setType(Context.IntTy); - break; - case Builtin::BI__builtin_constant_p: - if (checkArgCount(*this, TheCall, 1)) return true; - TheCall->setType(Context.IntTy); - break; - case Builtin::BI__sync_fetch_and_add: - case Builtin::BI__sync_fetch_and_add_1: - case Builtin::BI__sync_fetch_and_add_2: - case Builtin::BI__sync_fetch_and_add_4: - case Builtin::BI__sync_fetch_and_add_8: - case Builtin::BI__sync_fetch_and_add_16: - case Builtin::BI__sync_fetch_and_sub: - case Builtin::BI__sync_fetch_and_sub_1: - case Builtin::BI__sync_fetch_and_sub_2: - case Builtin::BI__sync_fetch_and_sub_4: - case Builtin::BI__sync_fetch_and_sub_8: - case Builtin::BI__sync_fetch_and_sub_16: - case Builtin::BI__sync_fetch_and_or: - case Builtin::BI__sync_fetch_and_or_1: - case Builtin::BI__sync_fetch_and_or_2: - case Builtin::BI__sync_fetch_and_or_4: - case Builtin::BI__sync_fetch_and_or_8: - case Builtin::BI__sync_fetch_and_or_16: - case Builtin::BI__sync_fetch_and_and: - case Builtin::BI__sync_fetch_and_and_1: - case Builtin::BI__sync_fetch_and_and_2: - case Builtin::BI__sync_fetch_and_and_4: - case Builtin::BI__sync_fetch_and_and_8: - case Builtin::BI__sync_fetch_and_and_16: - case Builtin::BI__sync_fetch_and_xor: - case Builtin::BI__sync_fetch_and_xor_1: - case Builtin::BI__sync_fetch_and_xor_2: - case Builtin::BI__sync_fetch_and_xor_4: - case Builtin::BI__sync_fetch_and_xor_8: - case Builtin::BI__sync_fetch_and_xor_16: - case Builtin::BI__sync_fetch_and_nand: - case Builtin::BI__sync_fetch_and_nand_1: - case Builtin::BI__sync_fetch_and_nand_2: - case Builtin::BI__sync_fetch_and_nand_4: - case Builtin::BI__sync_fetch_and_nand_8: - case Builtin::BI__sync_fetch_and_nand_16: - case Builtin::BI__sync_add_and_fetch: - case Builtin::BI__sync_add_and_fetch_1: - case Builtin::BI__sync_add_and_fetch_2: - case Builtin::BI__sync_add_and_fetch_4: - case Builtin::BI__sync_add_and_fetch_8: - case Builtin::BI__sync_add_and_fetch_16: - case Builtin::BI__sync_sub_and_fetch: - case Builtin::BI__sync_sub_and_fetch_1: - case Builtin::BI__sync_sub_and_fetch_2: - case Builtin::BI__sync_sub_and_fetch_4: - case Builtin::BI__sync_sub_and_fetch_8: - case Builtin::BI__sync_sub_and_fetch_16: - case Builtin::BI__sync_and_and_fetch: - case Builtin::BI__sync_and_and_fetch_1: - case Builtin::BI__sync_and_and_fetch_2: - case Builtin::BI__sync_and_and_fetch_4: - case Builtin::BI__sync_and_and_fetch_8: - case Builtin::BI__sync_and_and_fetch_16: - case Builtin::BI__sync_or_and_fetch: - case Builtin::BI__sync_or_and_fetch_1: - case Builtin::BI__sync_or_and_fetch_2: - case Builtin::BI__sync_or_and_fetch_4: - case Builtin::BI__sync_or_and_fetch_8: - case Builtin::BI__sync_or_and_fetch_16: - case Builtin::BI__sync_xor_and_fetch: - case Builtin::BI__sync_xor_and_fetch_1: - case Builtin::BI__sync_xor_and_fetch_2: - case Builtin::BI__sync_xor_and_fetch_4: - case Builtin::BI__sync_xor_and_fetch_8: - case Builtin::BI__sync_xor_and_fetch_16: - case Builtin::BI__sync_nand_and_fetch: - case Builtin::BI__sync_nand_and_fetch_1: - case Builtin::BI__sync_nand_and_fetch_2: - case Builtin::BI__sync_nand_and_fetch_4: - case Builtin::BI__sync_nand_and_fetch_8: - case Builtin::BI__sync_nand_and_fetch_16: - case Builtin::BI__sync_val_compare_and_swap: - case Builtin::BI__sync_val_compare_and_swap_1: - case Builtin::BI__sync_val_compare_and_swap_2: - case Builtin::BI__sync_val_compare_and_swap_4: - case Builtin::BI__sync_val_compare_and_swap_8: - case Builtin::BI__sync_val_compare_and_swap_16: - case Builtin::BI__sync_bool_compare_and_swap: - case Builtin::BI__sync_bool_compare_and_swap_1: - case Builtin::BI__sync_bool_compare_and_swap_2: - case Builtin::BI__sync_bool_compare_and_swap_4: - case Builtin::BI__sync_bool_compare_and_swap_8: - case Builtin::BI__sync_bool_compare_and_swap_16: - case Builtin::BI__sync_lock_test_and_set: - case Builtin::BI__sync_lock_test_and_set_1: - case Builtin::BI__sync_lock_test_and_set_2: - case Builtin::BI__sync_lock_test_and_set_4: - case Builtin::BI__sync_lock_test_and_set_8: - case Builtin::BI__sync_lock_test_and_set_16: - case Builtin::BI__sync_lock_release: - case Builtin::BI__sync_lock_release_1: - case Builtin::BI__sync_lock_release_2: - case Builtin::BI__sync_lock_release_4: - case Builtin::BI__sync_lock_release_8: - case Builtin::BI__sync_lock_release_16: - case Builtin::BI__sync_swap: - case Builtin::BI__sync_swap_1: - case Builtin::BI__sync_swap_2: - case Builtin::BI__sync_swap_4: - case Builtin::BI__sync_swap_8: - case Builtin::BI__sync_swap_16: - return SemaBuiltinAtomicOverloaded(TheCallResult); - case Builtin::BI__builtin_nontemporal_load: - case Builtin::BI__builtin_nontemporal_store: - return SemaBuiltinNontemporalOverloaded(TheCallResult); -#define BUILTIN(ID, TYPE, ATTRS) -#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ - case Builtin::BI##ID: \ - return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); -#include "clang/Basic/Builtins.def" - case Builtin::BI__annotation: - if (SemaBuiltinMSVCAnnotation(*this, TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_annotation: - if (SemaBuiltinAnnotation(*this, TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_addressof: - if (SemaBuiltinAddressof(*this, TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_add_overflow: - case Builtin::BI__builtin_sub_overflow: - case Builtin::BI__builtin_mul_overflow: - if (SemaBuiltinOverflow(*this, TheCall)) - return ExprError(); - break; - case Builtin::BI__builtin_operator_new: - case Builtin::BI__builtin_operator_delete: { - bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; - ExprResult Res = - SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); - if (Res.isInvalid()) - CorrectDelayedTyposInExpr(TheCallResult.get()); - return Res; - } - case Builtin::BI__builtin_dump_struct: { - // We first want to ensure we are called with 2 arguments - if (checkArgCount(*this, TheCall, 2)) - return ExprError(); - // Ensure that the first argument is of type 'struct XX *' - const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); - const QualType PtrArgType = PtrArg->getType(); - if (!PtrArgType->isPointerType() || - !PtrArgType->getPointeeType()->isRecordType()) { - Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) - << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType - << "structure pointer"; - return ExprError(); + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + Call->setType(S.Context.OCLReserveIDTy); + + return false; +} + +// Performs a semantic analysis on {work_group_/sub_group_ +// /_}commit_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // Check reserve_id_t. + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.OCLReserveIDTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// Performs a semantic analysis on the call to built-in Pipe +// Query Functions. +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 1)) + return true; + + if (!Call->getArg(0)->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); + return true; + } + + return false; +} + +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// Performs semantic analysis for the to_global/local/private call. +// \param S Reference to the semantic analyzer. +// \param BuiltinID ID of the builtin function. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, + CallExpr *Call) { + if (Call->getNumArgs() != 1) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + auto RT = Call->getArg(0)->getType(); + if (!RT->isPointerType() || RT->getPointeeType() + .getAddressSpace() == LangAS::opencl_constant) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg) + << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + RT = RT->getPointeeType(); + auto Qual = RT.getQualifiers(); + switch (BuiltinID) { + case Builtin::BIto_global: + Qual.setAddressSpace(LangAS::opencl_global); + break; + case Builtin::BIto_local: + Qual.setAddressSpace(LangAS::opencl_local); + break; + case Builtin::BIto_private: + Qual.setAddressSpace(LangAS::opencl_private); + break; + default: + llvm_unreachable("Invalid builtin function"); + } + Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( + RT.getUnqualifiedType(), Qual))); + + return false; +} + +// Emit an error and return true if the current architecture is not in the list +// of supported architectures. +static bool +CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef SupportedArchs) { + llvm::Triple::ArchType CurArch = + S.getASTContext().getTargetInfo().getTriple().getArch(); + if (llvm::is_contained(SupportedArchs, CurArch)) + return false; + S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported) + << TheCall->getSourceRange(); + return true; +} + +ExprResult +Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, + CallExpr *TheCall) { + ExprResult TheCallResult(TheCall); + + // Find out if any arguments are required to be integer constant expressions. + unsigned ICEArguments = 0; + ASTContext::GetBuiltinTypeError Error; + Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); + if (Error != ASTContext::GE_None) + ICEArguments = 0; // Don't diagnose previously diagnosed errors. + + // If any arguments are required to be ICE's, check and diagnose. + for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { + // Skip arguments not required to be ICE's. + if ((ICEArguments & (1 << ArgNo)) == 0) continue; + + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) + return true; + ICEArguments &= ~(1 << ArgNo); + } + + switch (BuiltinID) { + case Builtin::BI__builtin___CFStringMakeConstantString: + assert(TheCall->getNumArgs() == 1 && + "Wrong # arguments to builtin CFStringMakeConstantString"); + if (CheckObjCString(TheCall->getArg(0))) + return ExprError(); + break; + case Builtin::BI__builtin_ms_va_start: + case Builtin::BI__builtin_stdarg_start: + case Builtin::BI__builtin_va_start: + if (SemaBuiltinVAStart(BuiltinID, TheCall)) + return ExprError(); + break; + case Builtin::BI__va_start: { + switch (Context.getTargetInfo().getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (SemaBuiltinVAStartARMMicrosoft(TheCall)) + return ExprError(); + break; + default: + if (SemaBuiltinVAStart(BuiltinID, TheCall)) + return ExprError(); + break; + } + break; + } + + // The acquire, release, and no fence variants are ARM and AArch64 only. + case Builtin::BI_interlockedbittestandset_acq: + case Builtin::BI_interlockedbittestandset_rel: + case Builtin::BI_interlockedbittestandset_nf: + case Builtin::BI_interlockedbittestandreset_acq: + case Builtin::BI_interlockedbittestandreset_rel: + case Builtin::BI_interlockedbittestandreset_nf: + if (CheckBuiltinTargetSupport( + *this, BuiltinID, TheCall, + {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + + // The 64-bit bittest variants are x64, ARM, and AArch64 only. + case Builtin::BI_bittest64: + case Builtin::BI_bittestandcomplement64: + case Builtin::BI_bittestandreset64: + case Builtin::BI_bittestandset64: + case Builtin::BI_interlockedbittestandreset64: + case Builtin::BI_interlockedbittestandset64: + if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: + if (SemaBuiltinUnorderedCompare(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_fpclassify: + if (SemaBuiltinFPClassification(TheCall, 6)) + return ExprError(); + break; + case Builtin::BI__builtin_isfinite: + case Builtin::BI__builtin_isinf: + case Builtin::BI__builtin_isinf_sign: + case Builtin::BI__builtin_isnan: + case Builtin::BI__builtin_isnormal: + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: + if (SemaBuiltinFPClassification(TheCall, 1)) + return ExprError(); + break; + case Builtin::BI__builtin_shufflevector: + return SemaBuiltinShuffleVector(TheCall); + // TheCall will be freed by the smart pointer here, but that's fine, since + // SemaBuiltinShuffleVector guts it, but then doesn't release it. + case Builtin::BI__builtin_prefetch: + if (SemaBuiltinPrefetch(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_alloca_with_align: + if (SemaBuiltinAllocaWithAlign(TheCall)) + return ExprError(); + break; + case Builtin::BI__assume: + case Builtin::BI__builtin_assume: + if (SemaBuiltinAssume(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_assume_aligned: + if (SemaBuiltinAssumeAligned(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_object_size: + if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) + return ExprError(); + break; + case Builtin::BI__builtin_longjmp: + if (SemaBuiltinLongjmp(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_setjmp: + if (SemaBuiltinSetjmp(TheCall)) + return ExprError(); + break; + case Builtin::BI_setjmp: + case Builtin::BI_setjmpex: + if (checkArgCount(*this, TheCall, 1)) + return true; + break; + case Builtin::BI__builtin_classify_type: + if (checkArgCount(*this, TheCall, 1)) return true; + TheCall->setType(Context.IntTy); + break; + case Builtin::BI__builtin_constant_p: + if (checkArgCount(*this, TheCall, 1)) return true; + TheCall->setType(Context.IntTy); + break; + case Builtin::BI__sync_fetch_and_add: + case Builtin::BI__sync_fetch_and_add_1: + case Builtin::BI__sync_fetch_and_add_2: + case Builtin::BI__sync_fetch_and_add_4: + case Builtin::BI__sync_fetch_and_add_8: + case Builtin::BI__sync_fetch_and_add_16: + case Builtin::BI__sync_fetch_and_sub: + case Builtin::BI__sync_fetch_and_sub_1: + case Builtin::BI__sync_fetch_and_sub_2: + case Builtin::BI__sync_fetch_and_sub_4: + case Builtin::BI__sync_fetch_and_sub_8: + case Builtin::BI__sync_fetch_and_sub_16: + case Builtin::BI__sync_fetch_and_or: + case Builtin::BI__sync_fetch_and_or_1: + case Builtin::BI__sync_fetch_and_or_2: + case Builtin::BI__sync_fetch_and_or_4: + case Builtin::BI__sync_fetch_and_or_8: + case Builtin::BI__sync_fetch_and_or_16: + case Builtin::BI__sync_fetch_and_and: + case Builtin::BI__sync_fetch_and_and_1: + case Builtin::BI__sync_fetch_and_and_2: + case Builtin::BI__sync_fetch_and_and_4: + case Builtin::BI__sync_fetch_and_and_8: + case Builtin::BI__sync_fetch_and_and_16: + case Builtin::BI__sync_fetch_and_xor: + case Builtin::BI__sync_fetch_and_xor_1: + case Builtin::BI__sync_fetch_and_xor_2: + case Builtin::BI__sync_fetch_and_xor_4: + case Builtin::BI__sync_fetch_and_xor_8: + case Builtin::BI__sync_fetch_and_xor_16: + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: + case Builtin::BI__sync_add_and_fetch: + case Builtin::BI__sync_add_and_fetch_1: + case Builtin::BI__sync_add_and_fetch_2: + case Builtin::BI__sync_add_and_fetch_4: + case Builtin::BI__sync_add_and_fetch_8: + case Builtin::BI__sync_add_and_fetch_16: + case Builtin::BI__sync_sub_and_fetch: + case Builtin::BI__sync_sub_and_fetch_1: + case Builtin::BI__sync_sub_and_fetch_2: + case Builtin::BI__sync_sub_and_fetch_4: + case Builtin::BI__sync_sub_and_fetch_8: + case Builtin::BI__sync_sub_and_fetch_16: + case Builtin::BI__sync_and_and_fetch: + case Builtin::BI__sync_and_and_fetch_1: + case Builtin::BI__sync_and_and_fetch_2: + case Builtin::BI__sync_and_and_fetch_4: + case Builtin::BI__sync_and_and_fetch_8: + case Builtin::BI__sync_and_and_fetch_16: + case Builtin::BI__sync_or_and_fetch: + case Builtin::BI__sync_or_and_fetch_1: + case Builtin::BI__sync_or_and_fetch_2: + case Builtin::BI__sync_or_and_fetch_4: + case Builtin::BI__sync_or_and_fetch_8: + case Builtin::BI__sync_or_and_fetch_16: + case Builtin::BI__sync_xor_and_fetch: + case Builtin::BI__sync_xor_and_fetch_1: + case Builtin::BI__sync_xor_and_fetch_2: + case Builtin::BI__sync_xor_and_fetch_4: + case Builtin::BI__sync_xor_and_fetch_8: + case Builtin::BI__sync_xor_and_fetch_16: + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: + case Builtin::BI__sync_val_compare_and_swap: + case Builtin::BI__sync_val_compare_and_swap_1: + case Builtin::BI__sync_val_compare_and_swap_2: + case Builtin::BI__sync_val_compare_and_swap_4: + case Builtin::BI__sync_val_compare_and_swap_8: + case Builtin::BI__sync_val_compare_and_swap_16: + case Builtin::BI__sync_bool_compare_and_swap: + case Builtin::BI__sync_bool_compare_and_swap_1: + case Builtin::BI__sync_bool_compare_and_swap_2: + case Builtin::BI__sync_bool_compare_and_swap_4: + case Builtin::BI__sync_bool_compare_and_swap_8: + case Builtin::BI__sync_bool_compare_and_swap_16: + case Builtin::BI__sync_lock_test_and_set: + case Builtin::BI__sync_lock_test_and_set_1: + case Builtin::BI__sync_lock_test_and_set_2: + case Builtin::BI__sync_lock_test_and_set_4: + case Builtin::BI__sync_lock_test_and_set_8: + case Builtin::BI__sync_lock_test_and_set_16: + case Builtin::BI__sync_lock_release: + case Builtin::BI__sync_lock_release_1: + case Builtin::BI__sync_lock_release_2: + case Builtin::BI__sync_lock_release_4: + case Builtin::BI__sync_lock_release_8: + case Builtin::BI__sync_lock_release_16: + case Builtin::BI__sync_swap: + case Builtin::BI__sync_swap_1: + case Builtin::BI__sync_swap_2: + case Builtin::BI__sync_swap_4: + case Builtin::BI__sync_swap_8: + case Builtin::BI__sync_swap_16: + return SemaBuiltinAtomicOverloaded(TheCallResult); + case Builtin::BI__builtin_nontemporal_load: + case Builtin::BI__builtin_nontemporal_store: + return SemaBuiltinNontemporalOverloaded(TheCallResult); +#define BUILTIN(ID, TYPE, ATTRS) +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ + case Builtin::BI##ID: \ + return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); +#include "clang/Basic/Builtins.def" + case Builtin::BI__annotation: + if (SemaBuiltinMSVCAnnotation(*this, TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_annotation: + if (SemaBuiltinAnnotation(*this, TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_addressof: + if (SemaBuiltinAddressof(*this, TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + if (SemaBuiltinOverflow(*this, TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_operator_new: + case Builtin::BI__builtin_operator_delete: { + bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; + ExprResult Res = + SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + if (Res.isInvalid()) + CorrectDelayedTyposInExpr(TheCallResult.get()); + return Res; + } + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType() || + !PtrArgType->getPointeeType()->isRecordType()) { + Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType + << "structure pointer"; + return ExprError(); } // Ensure that the second argument is of type 'FunctionType' @@ -4392,415 +4395,419 @@ static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, return false; } -/// 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::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { - Expr *Fn = TheCall->getCallee(); - - if (checkVAStartABI(*this, BuiltinID, Fn)) - return true; - - if (TheCall->getNumArgs() > 2) { - Diag(TheCall->getArg(2)->getLocStart(), - diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << 2 << TheCall->getNumArgs() - << Fn->getSourceRange() - << SourceRange(TheCall->getArg(2)->getLocStart(), - (*(TheCall->arg_end()-1))->getLocEnd()); - return true; - } - - if (TheCall->getNumArgs() < 2) { - return Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_few_args_at_least) - << 0 /*function call*/ << 2 << TheCall->getNumArgs(); - } - - // Type-check the first argument normally. - if (checkBuiltinArgument(*this, TheCall, 0)) - return true; - - // Check that the current function is variadic, and get its last parameter. - ParmVarDecl *LastParam; - if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam)) - return true; - - // Verify that the second argument to the builtin is the last argument of the - // current function or method. - bool SecondArgIsLastNamedArgument = false; - const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); - - // These are valid if SecondArgIsLastNamedArgument is false after the next - // block. - QualType Type; - SourceLocation ParamLoc; - bool IsCRegister = false; - - if (const DeclRefExpr *DR = dyn_cast(Arg)) { - if (const ParmVarDecl *PV = dyn_cast(DR->getDecl())) { - SecondArgIsLastNamedArgument = PV == LastParam; - - Type = PV->getType(); - ParamLoc = PV->getLocation(); - IsCRegister = - PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; - } - } - - if (!SecondArgIsLastNamedArgument) - Diag(TheCall->getArg(1)->getLocStart(), - diag::warn_second_arg_of_va_start_not_last_named_param); - else if (IsCRegister || Type->isReferenceType() || - Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { - // Promotable integers are UB, but enumerations need a bit of - // extra checking to see what their promotable type actually is. - if (!Type->isPromotableIntegerType()) - return false; - if (!Type->isEnumeralType()) - return true; - const EnumDecl *ED = Type->getAs()->getDecl(); - return !(ED && - Context.typesAreCompatible(ED->getPromotionType(), Type)); - }()) { - unsigned Reason = 0; - if (Type->isReferenceType()) Reason = 1; - else if (IsCRegister) Reason = 2; - Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason; - Diag(ParamLoc, diag::note_parameter_type) << Type; - } - - TheCall->setType(Context.VoidTy); - return false; -} - -bool Sema::SemaBuiltinVAStartARMMicrosoft(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(); - - // Type-check the first argument normally. - if (checkBuiltinArgument(*this, Call, 0)) - return true; - - // Check that the current function is variadic. - if (checkVAStartIsInVariadicFunction(*this, Func)) - return true; - - // __va_start on Windows does not validate the parameter qualifiers - - const Expr *Arg1 = Call->getArg(1)->IgnoreParens(); - const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr(); - - const Expr *Arg2 = Call->getArg(2)->IgnoreParens(); - const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr(); - - const QualType &ConstCharPtrTy = - Context.getPointerType(Context.CharTy.withConst()); - if (!Arg1Ty->isPointerType() || - Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy) - Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible) - << Arg1->getType() << ConstCharPtrTy - << 1 /* different class */ - << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 2 << Arg1->getType() << ConstCharPtrTy; - - const QualType SizeTy = Context.getSizeType(); - if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy) - Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible) - << Arg2->getType() << SizeTy - << 1 /* different class */ - << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 3 << Arg2->getType() << SizeTy; - - 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) { - if (TheCall->getNumArgs() < 2) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << 2 << TheCall->getNumArgs()/*function call*/; - if (TheCall->getNumArgs() > 2) - return Diag(TheCall->getArg(2)->getLocStart(), - diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << 2 << TheCall->getNumArgs() - << SourceRange(TheCall->getArg(2)->getLocStart(), - (*(TheCall->arg_end()-1))->getLocEnd()); - - ExprResult OrigArg0 = TheCall->getArg(0); - ExprResult OrigArg1 = TheCall->getArg(1); - - // Do standard promotions between the two arguments, returning their common - // type. - QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); - if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) - return true; - - // Make sure any conversions are pushed back into the call; this is - // type safe since unordered compare builtins are declared as "_Bool - // foo(...)". - TheCall->setArg(0, OrigArg0.get()); - TheCall->setArg(1, OrigArg1.get()); - - if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent()) - return false; - - // If the common type isn't a real floating type, then the arguments were - // invalid for this operation. - if (Res.isNull() || !Res->isRealFloatingType()) - return Diag(OrigArg0.get()->getLocStart(), - diag::err_typecheck_call_invalid_ordered_compare) - << OrigArg0.get()->getType() << OrigArg1.get()->getType() - << SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd()); - - return false; -} - -/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like -/// __builtin_isnan and friends. This is declared to take (...), so we have -/// to check everything. We expect the last argument to be a floating point -/// value. -bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { - if (TheCall->getNumArgs() < NumArgs) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << NumArgs << TheCall->getNumArgs()/*function call*/; - if (TheCall->getNumArgs() > NumArgs) - return Diag(TheCall->getArg(NumArgs)->getLocStart(), - diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() - << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), - (*(TheCall->arg_end()-1))->getLocEnd()); - - Expr *OrigArg = TheCall->getArg(NumArgs-1); - - if (OrigArg->isTypeDependent()) - return false; - - // This operation requires a non-_Complex floating-point number. - if (!OrigArg->getType()->isRealFloatingType()) - return Diag(OrigArg->getLocStart(), - diag::err_typecheck_call_invalid_unary_fp) - << OrigArg->getType() << OrigArg->getSourceRange(); - - // If this is an implicit conversion from float -> float or double, remove it. - if (ImplicitCastExpr *Cast = dyn_cast(OrigArg)) { - // Only remove standard FloatCasts, leaving other casts inplace - if (Cast->getCastKind() == CK_FloatingCast) { - Expr *CastArg = Cast->getSubExpr(); - if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && - "promotion from float to either float or double is the only expected cast here"); - Cast->setSubExpr(nullptr); - TheCall->setArg(NumArgs-1, CastArg); - } - } - } - - return false; -} - -// Customized Sema Checking for VSX builtins that have the following signature: -// vector [...] builtinName(vector [...], vector [...], const int); -// Which takes the same type of vectors (any legal vector type) for the first -// two arguments and takes compile time constant for the third argument. -// Example builtins are : -// vector double vec_xxpermdi(vector double, vector double, int); -// vector short vec_xxsldwi(vector short, vector short, int); -bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { - unsigned ExpectedNumArgs = 3; - if (TheCall->getNumArgs() < ExpectedNumArgs) - return Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_few_args_at_least) - << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() - << TheCall->getSourceRange(); - - if (TheCall->getNumArgs() > ExpectedNumArgs) - return Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_many_args_at_most) - << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() - << TheCall->getSourceRange(); - - // Check the third argument is a compile time constant - llvm::APSInt Value; - if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context)) - return Diag(TheCall->getLocStart(), - diag::err_vsx_builtin_nonconstant_argument) - << 3 /* argument index */ << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(2)->getLocStart(), - TheCall->getArg(2)->getLocEnd()); - - QualType Arg1Ty = TheCall->getArg(0)->getType(); - QualType Arg2Ty = TheCall->getArg(1)->getType(); - - // Check the type of argument 1 and argument 2 are vectors. - SourceLocation BuiltinLoc = TheCall->getLocStart(); - if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || - (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { - return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(0)->getLocStart(), - TheCall->getArg(1)->getLocEnd()); - } - - // Check the first two arguments are the same type. - if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { - return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(0)->getLocStart(), - TheCall->getArg(1)->getLocEnd()); - } - - // When default clang type checking is turned off and the customized type - // checking is used, the returning type of the function must be explicitly - // set. Otherwise it is _Bool by default. - TheCall->setType(Arg1Ty); - - return false; -} - -/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. -// This is declared to take (...), so we have to check everything. -ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { - if (TheCall->getNumArgs() < 2) - return ExprError(Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_few_args_at_least) - << 0 /*function call*/ << 2 << TheCall->getNumArgs() - << TheCall->getSourceRange()); - - // Determine which of the following types of shufflevector we're checking: - // 1) unary, vector mask: (lhs, mask) - // 2) binary, scalar mask: (lhs, rhs, index, ..., index) - QualType resType = TheCall->getArg(0)->getType(); - unsigned numElements = 0; - - if (!TheCall->getArg(0)->isTypeDependent() && - !TheCall->getArg(1)->isTypeDependent()) { - QualType LHSType = TheCall->getArg(0)->getType(); - QualType RHSType = TheCall->getArg(1)->getType(); - - if (!LHSType->isVectorType() || !RHSType->isVectorType()) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(0)->getLocStart(), - TheCall->getArg(1)->getLocEnd())); - - numElements = LHSType->getAs()->getNumElements(); - unsigned numResElements = TheCall->getNumArgs() - 2; - - // Check to see if we have a call with 2 vector arguments, the unary shuffle - // with mask. If so, verify that RHS is an integer vector type with the - // same number of elts as lhs. - if (TheCall->getNumArgs() == 2) { - if (!RHSType->hasIntegerRepresentation() || - RHSType->getAs()->getNumElements() != numElements) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(1)->getLocStart(), - TheCall->getArg(1)->getLocEnd())); - } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { - return ExprError(Diag(TheCall->getLocStart(), - diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(0)->getLocStart(), - TheCall->getArg(1)->getLocEnd())); - } else if (numElements != numResElements) { - QualType eltType = LHSType->getAs()->getElementType(); - resType = Context.getVectorType(eltType, numResElements, - VectorType::GenericVector); - } - } - - for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { - if (TheCall->getArg(i)->isTypeDependent() || - TheCall->getArg(i)->isValueDependent()) - continue; - - llvm::APSInt Result(32); - if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_nonconstant_argument) - << TheCall->getArg(i)->getSourceRange()); - - // Allow -1 which will be translated to undef in the IR. - if (Result.isSigned() && Result.isAllOnesValue()) - continue; - - if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_argument_too_large) - << TheCall->getArg(i)->getSourceRange()); - } - - SmallVector exprs; - - for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { - exprs.push_back(TheCall->getArg(i)); - TheCall->setArg(i, nullptr); - } - - return new (Context) ShuffleVectorExpr(Context, exprs, resType, - TheCall->getCallee()->getLocStart(), - TheCall->getRParenLoc()); -} - -/// SemaConvertVectorExpr - Handle __builtin_convertvector -ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc) { - ExprValueKind VK = VK_RValue; - ExprObjectKind OK = OK_Ordinary; - QualType DstTy = TInfo->getType(); - QualType SrcTy = E->getType(); - - if (!SrcTy->isVectorType() && !SrcTy->isDependentType()) - return ExprError(Diag(BuiltinLoc, - diag::err_convertvector_non_vector) - << E->getSourceRange()); - if (!DstTy->isVectorType() && !DstTy->isDependentType()) - return ExprError(Diag(BuiltinLoc, - diag::err_convertvector_non_vector_type)); - - if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { - unsigned SrcElts = SrcTy->getAs()->getNumElements(); - unsigned DstElts = DstTy->getAs()->getNumElements(); - if (SrcElts != DstElts) - return ExprError(Diag(BuiltinLoc, - diag::err_convertvector_incompatible_vector) - << E->getSourceRange()); - } - - return new (Context) - ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc); -} - -/// SemaBuiltinPrefetch - Handle __builtin_prefetch. -// This is declared to take (const void*, ...) and can take two -// optional constant int args. -bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { - unsigned NumArgs = TheCall->getNumArgs(); - - if (NumArgs > 3) - return Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_many_args_at_most) - << 0 /*function call*/ << 3 << NumArgs - << TheCall->getSourceRange(); - - // Argument 0 is checked for us and the remaining arguments must be - // constant integers. - for (unsigned i = 1; i != NumArgs; ++i) +/// 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::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { + Expr *Fn = TheCall->getCallee(); + + if (checkVAStartABI(*this, BuiltinID, Fn)) + return true; + + if (TheCall->getNumArgs() > 2) { + Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << Fn->getSourceRange() + << SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + return true; + } + + if (TheCall->getNumArgs() < 2) { + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 2 << TheCall->getNumArgs(); + } + + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, TheCall, 0)) + return true; + + // Check that the current function is variadic, and get its last parameter. + ParmVarDecl *LastParam; + if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam)) + return true; + + // Verify that the second argument to the builtin is the last argument of the + // current function or method. + bool SecondArgIsLastNamedArgument = false; + const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); + + // These are valid if SecondArgIsLastNamedArgument is false after the next + // block. + QualType Type; + SourceLocation ParamLoc; + bool IsCRegister = false; + + if (const DeclRefExpr *DR = dyn_cast(Arg)) { + if (const ParmVarDecl *PV = dyn_cast(DR->getDecl())) { + SecondArgIsLastNamedArgument = PV == LastParam; + + Type = PV->getType(); + ParamLoc = PV->getLocation(); + IsCRegister = + PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; + } + } + + if (!SecondArgIsLastNamedArgument) + Diag(TheCall->getArg(1)->getLocStart(), + diag::warn_second_arg_of_va_start_not_last_named_param); + else if (IsCRegister || Type->isReferenceType() || + Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { + // Promotable integers are UB, but enumerations need a bit of + // extra checking to see what their promotable type actually is. + if (!Type->isPromotableIntegerType()) + return false; + if (!Type->isEnumeralType()) + return true; + const EnumDecl *ED = Type->getAs()->getDecl(); + return !(ED && + Context.typesAreCompatible(ED->getPromotionType(), Type)); + }()) { + unsigned Reason = 0; + if (Type->isReferenceType()) Reason = 1; + else if (IsCRegister) Reason = 2; + Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason; + Diag(ParamLoc, diag::note_parameter_type) << Type; + } + + TheCall->setType(Context.VoidTy); + return false; +} + +bool Sema::SemaBuiltinVAStartARMMicrosoft(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(); + + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, Call, 0)) + return true; + + // Check that the current function is variadic. + if (checkVAStartIsInVariadicFunction(*this, Func)) + return true; + + // __va_start on Windows does not validate the parameter qualifiers + + const Expr *Arg1 = Call->getArg(1)->IgnoreParens(); + const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr(); + + const Expr *Arg2 = Call->getArg(2)->IgnoreParens(); + const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr(); + + const QualType &ConstCharPtrTy = + Context.getPointerType(Context.CharTy.withConst()); + if (!Arg1Ty->isPointerType() || + Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy) + Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg1->getType() << ConstCharPtrTy + << 1 /* different class */ + << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << Arg1->getType() << ConstCharPtrTy; + + const QualType SizeTy = Context.getSizeType(); + if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy) + Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg2->getType() << SizeTy + << 1 /* different class */ + << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 3 << Arg2->getType() << SizeTy; + + 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) { + if (TheCall->getNumArgs() < 2) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << 2 << TheCall->getNumArgs()/*function call*/; + if (TheCall->getNumArgs() > 2) + return Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + + ExprResult OrigArg0 = TheCall->getArg(0); + ExprResult OrigArg1 = TheCall->getArg(1); + + // Do standard promotions between the two arguments, returning their common + // type. + QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) + return true; + + // Make sure any conversions are pushed back into the call; this is + // type safe since unordered compare builtins are declared as "_Bool + // foo(...)". + TheCall->setArg(0, OrigArg0.get()); + TheCall->setArg(1, OrigArg1.get()); + + if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent()) + return false; + + // If the common type isn't a real floating type, then the arguments were + // invalid for this operation. + if (Res.isNull() || !Res->isRealFloatingType()) + return Diag(OrigArg0.get()->getLocStart(), + diag::err_typecheck_call_invalid_ordered_compare) + << OrigArg0.get()->getType() << OrigArg1.get()->getType() + << SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd()); + + return false; +} + +/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like +/// __builtin_isnan and friends. This is declared to take (...), so we have +/// to check everything. We expect the last argument to be a floating point +/// value. +bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { + if (TheCall->getNumArgs() < NumArgs) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << NumArgs << TheCall->getNumArgs()/*function call*/; + if (TheCall->getNumArgs() > NumArgs) + return Diag(TheCall->getArg(NumArgs)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() + << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + + Expr *OrigArg = TheCall->getArg(NumArgs-1); + + if (OrigArg->isTypeDependent()) + return false; + + // This operation requires a non-_Complex floating-point number. + if (!OrigArg->getType()->isRealFloatingType()) + return Diag(OrigArg->getLocStart(), + diag::err_typecheck_call_invalid_unary_fp) + << OrigArg->getType() << OrigArg->getSourceRange(); + + // If this is an implicit conversion from float -> float, double, or + // long double, remove it. + if (ImplicitCastExpr *Cast = dyn_cast(OrigArg)) { + // Only remove standard FloatCasts, leaving other casts inplace + if (Cast->getCastKind() == CK_FloatingCast) { + Expr *CastArg = Cast->getSubExpr(); + if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { + assert( + (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && + "promotion from float to either float, double, or long double is " + "the only expected cast here"); + Cast->setSubExpr(nullptr); + TheCall->setArg(NumArgs-1, CastArg); + } + } + } + + return false; +} + +// Customized Sema Checking for VSX builtins that have the following signature: +// vector [...] builtinName(vector [...], vector [...], const int); +// Which takes the same type of vectors (any legal vector type) for the first +// two arguments and takes compile time constant for the third argument. +// Example builtins are : +// vector double vec_xxpermdi(vector double, vector double, int); +// vector short vec_xxsldwi(vector short, vector short, int); +bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { + unsigned ExpectedNumArgs = 3; + if (TheCall->getNumArgs() < ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + if (TheCall->getNumArgs() > ExpectedNumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + // Check the third argument is a compile time constant + llvm::APSInt Value; + if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context)) + return Diag(TheCall->getLocStart(), + diag::err_vsx_builtin_nonconstant_argument) + << 3 /* argument index */ << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(2)->getLocStart(), + TheCall->getArg(2)->getLocEnd()); + + QualType Arg1Ty = TheCall->getArg(0)->getType(); + QualType Arg2Ty = TheCall->getArg(1)->getType(); + + // Check the type of argument 1 and argument 2 are vectors. + SourceLocation BuiltinLoc = TheCall->getLocStart(); + if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || + (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { + return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // Check the first two arguments are the same type. + if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { + return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // When default clang type checking is turned off and the customized type + // checking is used, the returning type of the function must be explicitly + // set. Otherwise it is _Bool by default. + TheCall->setType(Arg1Ty); + + return false; +} + +/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. +// This is declared to take (...), so we have to check everything. +ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 2) + return ExprError(Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << TheCall->getSourceRange()); + + // Determine which of the following types of shufflevector we're checking: + // 1) unary, vector mask: (lhs, mask) + // 2) binary, scalar mask: (lhs, rhs, index, ..., index) + QualType resType = TheCall->getArg(0)->getType(); + unsigned numElements = 0; + + if (!TheCall->getArg(0)->isTypeDependent() && + !TheCall->getArg(1)->isTypeDependent()) { + QualType LHSType = TheCall->getArg(0)->getType(); + QualType RHSType = TheCall->getArg(1)->getType(); + + if (!LHSType->isVectorType() || !RHSType->isVectorType()) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd())); + + numElements = LHSType->getAs()->getNumElements(); + unsigned numResElements = TheCall->getNumArgs() - 2; + + // Check to see if we have a call with 2 vector arguments, the unary shuffle + // with mask. If so, verify that RHS is an integer vector type with the + // same number of elts as lhs. + if (TheCall->getNumArgs() == 2) { + if (!RHSType->hasIntegerRepresentation() || + RHSType->getAs()->getNumElements() != numElements) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(1)->getLocStart(), + TheCall->getArg(1)->getLocEnd())); + } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { + return ExprError(Diag(TheCall->getLocStart(), + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd())); + } else if (numElements != numResElements) { + QualType eltType = LHSType->getAs()->getElementType(); + resType = Context.getVectorType(eltType, numResElements, + VectorType::GenericVector); + } + } + + for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { + if (TheCall->getArg(i)->isTypeDependent() || + TheCall->getArg(i)->isValueDependent()) + continue; + + llvm::APSInt Result(32); + if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_shufflevector_nonconstant_argument) + << TheCall->getArg(i)->getSourceRange()); + + // Allow -1 which will be translated to undef in the IR. + if (Result.isSigned() && Result.isAllOnesValue()) + continue; + + if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_shufflevector_argument_too_large) + << TheCall->getArg(i)->getSourceRange()); + } + + SmallVector exprs; + + for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { + exprs.push_back(TheCall->getArg(i)); + TheCall->setArg(i, nullptr); + } + + return new (Context) ShuffleVectorExpr(Context, exprs, resType, + TheCall->getCallee()->getLocStart(), + TheCall->getRParenLoc()); +} + +/// SemaConvertVectorExpr - Handle __builtin_convertvector +ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; + QualType DstTy = TInfo->getType(); + QualType SrcTy = E->getType(); + + if (!SrcTy->isVectorType() && !SrcTy->isDependentType()) + return ExprError(Diag(BuiltinLoc, + diag::err_convertvector_non_vector) + << E->getSourceRange()); + if (!DstTy->isVectorType() && !DstTy->isDependentType()) + return ExprError(Diag(BuiltinLoc, + diag::err_convertvector_non_vector_type)); + + if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { + unsigned SrcElts = SrcTy->getAs()->getNumElements(); + unsigned DstElts = DstTy->getAs()->getNumElements(); + if (SrcElts != DstElts) + return ExprError(Diag(BuiltinLoc, + diag::err_convertvector_incompatible_vector) + << E->getSourceRange()); + } + + return new (Context) + ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc); +} + +/// SemaBuiltinPrefetch - Handle __builtin_prefetch. +// This is declared to take (const void*, ...) and can take two +// optional constant int args. +bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs > 3) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 3 << NumArgs + << TheCall->getSourceRange(); + + // Argument 0 is checked for us and the remaining arguments must be + // constant integers. + for (unsigned i = 1; i != NumArgs; ++i) if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) return true; diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c index 7e999991f3..893a4459f7 100644 --- a/test/Sema/builtins.c +++ b/test/Sema/builtins.c @@ -53,203 +53,226 @@ void test9(short v) { // overloaded atomics should be declared only once. void test9_1(volatile int* ptr, int val) { - __sync_fetch_and_add_4(ptr, val); -} -void test9_2(volatile int* ptr, int val) { - __sync_fetch_and_add(ptr, val); -} -void test9_3(volatile int* ptr, int val) { - __sync_fetch_and_add_4(ptr, val); - __sync_fetch_and_add(ptr, val); - __sync_fetch_and_add(ptr, val); - __sync_fetch_and_add_4(ptr, val); - __sync_fetch_and_add_4(ptr, val); -} - -void test9_4(volatile int* ptr, int val) { - // expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}} - __sync_fetch_and_nand(ptr, val); -} - -// rdar://7236819 -void test10(void) __attribute__((noreturn)); - -void test10(void) { - __asm__("int3"); - __builtin_unreachable(); - - // No warning about falling off the end of a noreturn function. -} - -void test11(int X) { - switch (X) { - case __builtin_eh_return_data_regno(0): // constant foldable. - break; - } - - __builtin_eh_return_data_regno(X); // expected-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}} -} - -// PR5062 -void test12(void) __attribute__((__noreturn__)); -void test12(void) { - __builtin_trap(); // no warning because trap is noreturn. -} - -void test_unknown_builtin(int a, int b) { - __builtin_isles(a, b); // expected-error{{use of unknown builtin}} \ - // expected-note{{did you mean '__builtin_isless'?}} -} - -int test13() { - __builtin_eh_return(0, 0); // no warning, eh_return never returns. -} - -// -void test14() { - int old; - old = __sync_fetch_and_min((volatile int *)&old, 1); -} - -// -void test15(const char *s) { - __builtin_printf("string is %s\n", s); -} - -// PR7885 -int test16() { - return __builtin_constant_p() + // expected-error{{too few arguments}} - __builtin_constant_p(1, 2); // expected-error {{too many arguments}} -} - -const int test17_n = 0; -const char test17_c[] = {1, 2, 3, 0}; -const char test17_d[] = {1, 2, 3, 4}; -typedef int __attribute__((vector_size(16))) IntVector; -struct Aggregate { int n; char c; }; -enum Enum { EnumValue1, EnumValue2 }; - -typedef __typeof(sizeof(int)) size_t; -size_t strlen(const char *); - -void test17() { -#define ASSERT(...) { int arr[(__VA_ARGS__) ? 1 : -1]; } -#define T(...) ASSERT(__builtin_constant_p(__VA_ARGS__)) -#define F(...) ASSERT(!__builtin_constant_p(__VA_ARGS__)) - - // __builtin_constant_p returns 1 if the argument folds to: - // - an arithmetic constant with value which is known at compile time - T(test17_n); - T(&test17_c[3] - test17_c); - T(3i + 5); // expected-warning {{imaginary constant}} - T(4.2 * 7.6); - T(EnumValue1); - T((enum Enum)(int)EnumValue2); - - // - the address of the first character of a string literal, losslessly cast - // to any type - T("string literal"); - T((double*)"string literal"); - T("string literal" + 0); - T((long)"string literal"); - - // ... and otherwise returns 0. - F("string literal" + 1); - F(&test17_n); - F(test17_c); - F(&test17_c); - F(&test17_d); - F((struct Aggregate){0, 1}); - F((IntVector){0, 1, 2, 3}); - - // Ensure that a technique used in glibc is handled correctly. -#define OPT(...) (__builtin_constant_p(__VA_ARGS__) && strlen(__VA_ARGS__) < 4) - // FIXME: These are incorrectly treated as ICEs because strlen is treated as - // a builtin. - ASSERT(OPT("abc")); - ASSERT(!OPT("abcd")); - // In these cases, the strlen is non-constant, but the __builtin_constant_p - // is 0: the array size is not an ICE but is foldable. - ASSERT(!OPT(test17_c)); // expected-warning {{folded}} - ASSERT(!OPT(&test17_c[0])); // expected-warning {{folded}} - ASSERT(!OPT((char*)test17_c)); // expected-warning {{folded}} - ASSERT(!OPT(test17_d)); // expected-warning {{folded}} - ASSERT(!OPT(&test17_d[0])); // expected-warning {{folded}} - ASSERT(!OPT((char*)test17_d)); // expected-warning {{folded}} - -#undef OPT -#undef T -#undef F -} - -void test18() { - char src[1024]; - char dst[2048]; - size_t result; - void *ptr; - - ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src), sizeof(dst)); - result = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst)); - result = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst)); - - ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src)); // expected-error {{too few arguments to function call}} - ptr = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}} - ptr = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}} -} - -void no_ms_builtins() { - __assume(1); // expected-warning {{implicit declaration}} - __noop(1); // expected-warning {{implicit declaration}} - __debugbreak(); // expected-warning {{implicit declaration}} -} - -void unavailable() { - __builtin_operator_new(0); // expected-error {{'__builtin_operator_new' is only available in C++}} - __builtin_operator_delete(0); // expected-error {{'__builtin_operator_delete' is only available in C++}} -} - -// rdar://18259539 -size_t strlcpy(char * restrict dst, const char * restrict src, size_t size); -size_t strlcat(char * restrict dst, const char * restrict src, size_t size); - -void Test19(void) -{ - static char b[40]; - static char buf[20]; - - strlcpy(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \\ - // expected-note {{change size argument to be the size of the destination}} - __builtin___strlcpy_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcpy_chk' call appears to be size of the source; expected the size of the destination}} \ - // expected-note {{change size argument to be the size of the destination}} \ - // expected-warning {{'__builtin___strlcpy_chk' will always overflow destination buffer}} - - strlcat(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcat' call appears to be size of the source; expected the size of the destination}} \ - // expected-note {{change size argument to be the size of the destination}} - - __builtin___strlcat_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcat_chk' call appears to be size of the source; expected the size of the destination}} \ - // expected-note {{change size argument to be the size of the destination}} \ - // expected-warning {{'__builtin___strlcat_chk' will always overflow destination buffer}} -} - -// rdar://11076881 -char * Test20(char *p, const char *in, unsigned n) -{ - static char buf[10]; - - __builtin___memcpy_chk (&buf[6], in, 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}} - - __builtin___memcpy_chk (p, "abcde", n, __builtin_object_size (p, 0)); - - __builtin___memcpy_chk (&buf[5], "abcde", 5, __builtin_object_size (&buf[5], 0)); - - __builtin___memcpy_chk (&buf[5], "abcde", n, __builtin_object_size (&buf[5], 0)); - - __builtin___memcpy_chk (&buf[6], "abcde", 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}} - - return buf; -} - -void test21(const int *ptr) { - __sync_fetch_and_add(ptr, 1); // expected-error{{address argument to atomic builtin cannot be const-qualified ('const int *' invalid)}} - __atomic_fetch_add(ptr, 1, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const int *' invalid)}} -} + __sync_fetch_and_add_4(ptr, val); +} +void test9_2(volatile int* ptr, int val) { + __sync_fetch_and_add(ptr, val); +} +void test9_3(volatile int* ptr, int val) { + __sync_fetch_and_add_4(ptr, val); + __sync_fetch_and_add(ptr, val); + __sync_fetch_and_add(ptr, val); + __sync_fetch_and_add_4(ptr, val); + __sync_fetch_and_add_4(ptr, val); +} + +void test9_4(volatile int* ptr, int val) { + // expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}} + __sync_fetch_and_nand(ptr, val); +} + +// rdar://7236819 +void test10(void) __attribute__((noreturn)); + +void test10(void) { + __asm__("int3"); + __builtin_unreachable(); + + // No warning about falling off the end of a noreturn function. +} + +void test11(int X) { + switch (X) { + case __builtin_eh_return_data_regno(0): // constant foldable. + break; + } + + __builtin_eh_return_data_regno(X); // expected-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}} +} + +// PR5062 +void test12(void) __attribute__((__noreturn__)); +void test12(void) { + __builtin_trap(); // no warning because trap is noreturn. +} + +void test_unknown_builtin(int a, int b) { + __builtin_isles(a, b); // expected-error{{use of unknown builtin}} \ + // expected-note{{did you mean '__builtin_isless'?}} +} + +int test13() { + __builtin_eh_return(0, 0); // no warning, eh_return never returns. +} + +// +void test14() { + int old; + old = __sync_fetch_and_min((volatile int *)&old, 1); +} + +// +void test15(const char *s) { + __builtin_printf("string is %s\n", s); +} + +// PR7885 +int test16() { + return __builtin_constant_p() + // expected-error{{too few arguments}} + __builtin_constant_p(1, 2); // expected-error {{too many arguments}} +} + +const int test17_n = 0; +const char test17_c[] = {1, 2, 3, 0}; +const char test17_d[] = {1, 2, 3, 4}; +typedef int __attribute__((vector_size(16))) IntVector; +struct Aggregate { int n; char c; }; +enum Enum { EnumValue1, EnumValue2 }; + +typedef __typeof(sizeof(int)) size_t; +size_t strlen(const char *); + +void test17() { +#define ASSERT(...) { int arr[(__VA_ARGS__) ? 1 : -1]; } +#define T(...) ASSERT(__builtin_constant_p(__VA_ARGS__)) +#define F(...) ASSERT(!__builtin_constant_p(__VA_ARGS__)) + + // __builtin_constant_p returns 1 if the argument folds to: + // - an arithmetic constant with value which is known at compile time + T(test17_n); + T(&test17_c[3] - test17_c); + T(3i + 5); // expected-warning {{imaginary constant}} + T(4.2 * 7.6); + T(EnumValue1); + T((enum Enum)(int)EnumValue2); + + // - the address of the first character of a string literal, losslessly cast + // to any type + T("string literal"); + T((double*)"string literal"); + T("string literal" + 0); + T((long)"string literal"); + + // ... and otherwise returns 0. + F("string literal" + 1); + F(&test17_n); + F(test17_c); + F(&test17_c); + F(&test17_d); + F((struct Aggregate){0, 1}); + F((IntVector){0, 1, 2, 3}); + + // Ensure that a technique used in glibc is handled correctly. +#define OPT(...) (__builtin_constant_p(__VA_ARGS__) && strlen(__VA_ARGS__) < 4) + // FIXME: These are incorrectly treated as ICEs because strlen is treated as + // a builtin. + ASSERT(OPT("abc")); + ASSERT(!OPT("abcd")); + // In these cases, the strlen is non-constant, but the __builtin_constant_p + // is 0: the array size is not an ICE but is foldable. + ASSERT(!OPT(test17_c)); // expected-warning {{folded}} + ASSERT(!OPT(&test17_c[0])); // expected-warning {{folded}} + ASSERT(!OPT((char*)test17_c)); // expected-warning {{folded}} + ASSERT(!OPT(test17_d)); // expected-warning {{folded}} + ASSERT(!OPT(&test17_d[0])); // expected-warning {{folded}} + ASSERT(!OPT((char*)test17_d)); // expected-warning {{folded}} + +#undef OPT +#undef T +#undef F +} + +void test18() { + char src[1024]; + char dst[2048]; + size_t result; + void *ptr; + + ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src), sizeof(dst)); + result = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst)); + result = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst)); + + ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src)); // expected-error {{too few arguments to function call}} + ptr = __builtin___strlcpy_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}} + ptr = __builtin___strlcat_chk(dst, src, sizeof(dst), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}} +} + +void no_ms_builtins() { + __assume(1); // expected-warning {{implicit declaration}} + __noop(1); // expected-warning {{implicit declaration}} + __debugbreak(); // expected-warning {{implicit declaration}} +} + +void unavailable() { + __builtin_operator_new(0); // expected-error {{'__builtin_operator_new' is only available in C++}} + __builtin_operator_delete(0); // expected-error {{'__builtin_operator_delete' is only available in C++}} +} + +// rdar://18259539 +size_t strlcpy(char * restrict dst, const char * restrict src, size_t size); +size_t strlcat(char * restrict dst, const char * restrict src, size_t size); + +void Test19(void) +{ + static char b[40]; + static char buf[20]; + + strlcpy(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \\ + // expected-note {{change size argument to be the size of the destination}} + __builtin___strlcpy_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcpy_chk' call appears to be size of the source; expected the size of the destination}} \ + // expected-note {{change size argument to be the size of the destination}} \ + // expected-warning {{'__builtin___strlcpy_chk' will always overflow destination buffer}} + + strlcat(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcat' call appears to be size of the source; expected the size of the destination}} \ + // expected-note {{change size argument to be the size of the destination}} + + __builtin___strlcat_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcat_chk' call appears to be size of the source; expected the size of the destination}} \ + // expected-note {{change size argument to be the size of the destination}} \ + // expected-warning {{'__builtin___strlcat_chk' will always overflow destination buffer}} +} + +// rdar://11076881 +char * Test20(char *p, const char *in, unsigned n) +{ + static char buf[10]; + + __builtin___memcpy_chk (&buf[6], in, 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}} + + __builtin___memcpy_chk (p, "abcde", n, __builtin_object_size (p, 0)); + + __builtin___memcpy_chk (&buf[5], "abcde", 5, __builtin_object_size (&buf[5], 0)); + + __builtin___memcpy_chk (&buf[5], "abcde", n, __builtin_object_size (&buf[5], 0)); + + __builtin___memcpy_chk (&buf[6], "abcde", 5, __builtin_object_size (&buf[6], 0)); // expected-warning {{'__builtin___memcpy_chk' will always overflow destination buffer}} + + return buf; +} + +void test21(const int *ptr) { + __sync_fetch_and_add(ptr, 1); // expected-error{{address argument to atomic builtin cannot be const-qualified ('const int *' invalid)}} + __atomic_fetch_add(ptr, 1, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const int *' invalid)}} +} + +void test22(void) { + (void)__builtin_signbit(); // expected-error{{too few arguments to function call, expected 1, have 0}} + (void)__builtin_signbit(1.0, 2.0, 3.0); // expected-error{{too many arguments to function call, expected 1, have 3}} + (void)__builtin_signbit(1); // expected-error {{floating point classification requires argument of floating point type (passed in 'int')}} + (void)__builtin_signbit(1.0); + (void)__builtin_signbit(1.0f); + (void)__builtin_signbit(1.0L); + + (void)__builtin_signbitf(); // expected-error{{too few arguments to function call, expected 1, have 0}} + (void)__builtin_signbitf(1.0, 2.0, 3.0); // expected-error{{too many arguments to function call, expected 1, have 3}} + (void)__builtin_signbitf(1); + (void)__builtin_signbitf(1.0); + (void)__builtin_signbitf(1.0f); + (void)__builtin_signbitf(1.0L); + + (void)__builtin_signbitl(); // expected-error{{too few arguments to function call, expected 1, have 0}} + (void)__builtin_signbitl(1.0, 2.0, 3.0); // expected-error{{too many arguments to function call, expected 1, have 3}} + (void)__builtin_signbitl(1); + (void)__builtin_signbitl(1.0); + (void)__builtin_signbitl(1.0f); + (void)__builtin_signbitl(1.0L); +} -- 2.40.0