diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-08-16 21:17:51 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-08-16 21:17:51 +0000 |
commit | e7145dcb9f6563389ebbfa0572ef7589bdd94b1b (patch) | |
tree | b1b30c4998f6e9769784be87d402e4f8db13e34d /contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp | |
parent | 3ca95b020283db6244cab92ede73c969253b6a31 (diff) | |
parent | 7fd6ba58d980ec2bf312a80444948501dd27d020 (diff) |
Update clang to release_39 branch r276489, and resolve conflicts.
Notes
Notes:
svn path=/projects/clang390-import/; revision=304241
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp | 1891 |
1 files changed, 1446 insertions, 445 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 6c2834b750ae..0c25e01787c1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -36,9 +36,12 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Locale.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include <limits> + using namespace clang; using namespace sema; @@ -258,6 +261,459 @@ static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, return false; } +static inline bool isBlockPointer(Expr *Arg) { + return Arg->getType()->isBlockPointerType(); +} + +/// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local +/// void*, which is a requirement of device side enqueue. +static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { + const BlockPointerType *BPT = + cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); + ArrayRef<QualType> Params = + BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes(); + unsigned ArgCounter = 0; + bool IllegalParams = false; + // Iterate through the block parameters until either one is found that is not + // a local void*, or the block is valid. + for (ArrayRef<QualType>::iterator I = Params.begin(), E = Params.end(); + I != E; ++I, ++ArgCounter) { + if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || + (*I)->getPointeeType().getQualifiers().getAddressSpace() != + LangAS::opencl_local) { + // Get the location of the error. If a block literal has been passed + // (BlockExpr) then we can point straight to the offending argument, + // else we just point to the variable reference. + SourceLocation ErrorLoc; + if (isa<BlockExpr>(BlockArg)) { + BlockDecl *BD = cast<BlockExpr>(BlockArg)->getBlockDecl(); + ErrorLoc = BD->getParamDecl(ArgCounter)->getLocStart(); + } else if (isa<DeclRefExpr>(BlockArg)) { + ErrorLoc = cast<DeclRefExpr>(BlockArg)->getLocStart(); + } + S.Diag(ErrorLoc, + diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); + IllegalParams = true; + } + } + + return IllegalParams; +} + +/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the +/// get_kernel_work_group_size +/// and get_kernel_preferred_work_group_size_multiple builtin functions. +static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { + if (checkArgCount(S, TheCall, 1)) + return true; + + Expr *BlockArg = TheCall->getArg(0); + if (!isBlockPointer(BlockArg)) { + S.Diag(BlockArg->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) << "block"; + return true; + } + return checkOpenCLBlockArgs(S, BlockArg); +} + +static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, + unsigned Start, unsigned End); + +/// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all +/// 'local void*' parameter of passed block. +static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, + Expr *BlockArg, + unsigned NumNonVarArgs) { + const BlockPointerType *BPT = + cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); + unsigned NumBlockParams = + BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams(); + unsigned TotalNumArgs = TheCall->getNumArgs(); + + // For each argument passed to the block, a corresponding uint needs to + // be passed to describe the size of the local memory. + if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { + S.Diag(TheCall->getLocStart(), + diag::err_opencl_enqueue_kernel_local_size_args); + return true; + } + + // Check that the sizes of the local memory are specified by integers. + return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, + TotalNumArgs - 1); +} + +/// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different +/// overload formats specified in Table 6.13.17.1. +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// void (^block)(void)) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// uint num_events_in_wait_list, +/// clk_event_t *event_wait_list, +/// clk_event_t *event_ret, +/// void (^block)(void)) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// void (^block)(local void*, ...), +/// uint size0, ...) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// uint num_events_in_wait_list, +/// clk_event_t *event_wait_list, +/// clk_event_t *event_ret, +/// void (^block)(local void*, ...), +/// uint size0, ...) +static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs < 4) { + S.Diag(TheCall->getLocStart(), diag::err_typecheck_call_too_few_args); + return true; + } + + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + Expr *Arg3 = TheCall->getArg(3); + + // First argument always needs to be a queue_t type. + if (!Arg0->getType()->isQueueT()) { + S.Diag(TheCall->getArg(0)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.OCLQueueTy; + return true; + } + + // Second argument always needs to be a kernel_enqueue_flags_t enum value. + if (!Arg1->getType()->isIntegerType()) { + S.Diag(TheCall->getArg(1)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << "'kernel_enqueue_flags_t' (i.e. uint)"; + return true; + } + + // Third argument is always an ndrange_t type. + if (!Arg2->getType()->isNDRangeT()) { + S.Diag(TheCall->getArg(2)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.OCLNDRangeTy; + return true; + } + + // With four arguments, there is only one form that the function could be + // called in: no events and no variable arguments. + if (NumArgs == 4) { + // check that the last argument is the right block type. + if (!isBlockPointer(Arg3)) { + S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) + << "block"; + return true; + } + // we have a block type, check the prototype + const BlockPointerType *BPT = + cast<BlockPointerType>(Arg3->getType().getCanonicalType()); + if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) { + S.Diag(Arg3->getLocStart(), + diag::err_opencl_enqueue_kernel_blocks_no_args); + return true; + } + return false; + } + // we can have block + varargs. + if (isBlockPointer(Arg3)) + return (checkOpenCLBlockArgs(S, Arg3) || + checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg3, 4)); + // last two cases with either exactly 7 args or 7 args and varargs. + if (NumArgs >= 7) { + // check common block argument. + Expr *Arg6 = TheCall->getArg(6); + if (!isBlockPointer(Arg6)) { + S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) + << "block"; + return true; + } + if (checkOpenCLBlockArgs(S, Arg6)) + return true; + + // Forth argument has to be any integer type. + if (!Arg3->getType()->isIntegerType()) { + S.Diag(TheCall->getArg(3)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << "integer"; + return true; + } + // check remaining common arguments. + Expr *Arg4 = TheCall->getArg(4); + Expr *Arg5 = TheCall->getArg(5); + + // Fith argument is always passed as pointers to clk_event_t. + if (!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { + S.Diag(TheCall->getArg(4)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.getPointerType(S.Context.OCLClkEventTy); + return true; + } + + // Sixth argument is always passed as pointers to clk_event_t. + if (!(Arg5->getType()->isPointerType() && + Arg5->getType()->getPointeeType()->isClkEventT())) { + S.Diag(TheCall->getArg(5)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.getPointerType(S.Context.OCLClkEventTy); + return true; + } + + if (NumArgs == 7) + return false; + + return checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg6, 7); + } + + // None of the specific case has been detected, give generic error + S.Diag(TheCall->getLocStart(), + diag::err_opencl_enqueue_kernel_incorrect_args); + return true; +} + +/// Returns OpenCL access qual. +static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { + return D->getAttr<OpenCLAccessAttr>(); +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { + const Expr *Arg0 = Call->getArg(0); + // First argument type should always be pipe. + if (!Arg0->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Arg0->getSourceRange(); + return true; + } + OpenCLAccessAttr *AccessQual = + getOpenCLArgAccess(cast<DeclRefExpr>(Arg0)->getDecl()); + // Validates the access qualifier is compatible with the call. + // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be + // read_only and write_only, and assumed to be read_only if no qualifier is + // specified. + switch (Call->getDirectCallee()->getBuiltinID()) { + case Builtin::BIread_pipe: + case Builtin::BIreserve_read_pipe: + case Builtin::BIcommit_read_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIsub_group_commit_read_pipe: + if (!(!AccessQual || AccessQual->isReadOnly())) { + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "read_only" << Arg0->getSourceRange(); + return true; + } + break; + case Builtin::BIwrite_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (!(AccessQual && AccessQual->isWriteOnly())) { + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "write_only" << Arg0->getSourceRange(); + return true; + } + break; + default: + break; + } + return false; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { + const Expr *Arg0 = Call->getArg(0); + const Expr *ArgIdx = Call->getArg(Idx); + const PipeType *PipeTy = cast<PipeType>(Arg0->getType()); + const QualType EltTy = PipeTy->getElementType(); + const PointerType *ArgTy = ArgIdx->getType()->getAs<PointerType>(); + // The Idx argument should be a pointer and the type of the pointer and + // the type of pipe element should also be the same. + if (!ArgTy || + !S.Context.hasSameType( + EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.getPointerType(EltTy) + << ArgIdx->getType() << ArgIdx->getSourceRange(); + return true; + } + return false; +} + +// \brief Performs semantic analysis for the read/write_pipe call. +// \param S Reference to the semantic analyzer. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { + // OpenCL v2.0 s6.13.16.2 - The built-in read/write + // functions have two forms. + switch (Call->getNumArgs()) { + case 2: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 2 arguments should be + // read/write_pipe(pipe T, T*). + // Check packet type T. + if (checkOpenCLPipePacketType(S, Call, 1)) + return true; + } break; + + case 4: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 4 arguments should be + // read/write_pipe(pipe T, reserve_id_t, uint, T*). + // 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; + } + + // Check the index. + const Expr *Arg2 = Call->getArg(2); + if (!Arg2->getType()->isIntegerType() && + !Arg2->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.UnsignedIntTy + << Arg2->getType() << Arg2->getSourceRange(); + return true; + } + + // Check packet type T. + if (checkOpenCLPipePacketType(S, Call, 3)) + return true; + } break; + default: + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// /_}reserve_{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 SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // Check the reserve size. + if (!Call->getArg(1)->getType()->isIntegerType() && + !Call->getArg(1)->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.UnsignedIntTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief 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; +} + +// \brief 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; +} +// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// \brief 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; + default: + Qual.removeAddressSpace(); + } + Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( + RT.getUnqualifiedType(), Qual))); + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -530,27 +986,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin___vsnprintf_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); break; - case Builtin::BI__builtin_call_with_static_chain: if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; - case Builtin::BI__exception_code: - case Builtin::BI_exception_code: { + case Builtin::BI_exception_code: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, diag::err_seh___except_block)) return ExprError(); break; - } case Builtin::BI__exception_info: - case Builtin::BI_exception_info: { + case Builtin::BI_exception_info: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, diag::err_seh___except_filter)) return ExprError(); break; - } - case Builtin::BI__GetExceptionInfo: if (checkArgCount(*this, TheCall, 1)) return ExprError(); @@ -563,7 +1014,56 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.VoidPtrTy); break; - + // OpenCL v2.0, s6.13.16 - Pipe functions + case Builtin::BIread_pipe: + case Builtin::BIwrite_pipe: + // Since those two functions are declared with var args, we need a semantic + // check for the argument. + if (SemaBuiltinRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIreserve_read_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + // 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. + TheCall->setType(Context.OCLReserveIDTy); + break; + case Builtin::BIcommit_read_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_read_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_pipe_num_packets: + case Builtin::BIget_pipe_max_packets: + if (SemaBuiltinPipePackets(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIto_global: + case Builtin::BIto_local: + case Builtin::BIto_private: + if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) + return ExprError(); + break; + // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. + case Builtin::BIenqueue_kernel: + if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_kernel_work_group_size: + case Builtin::BIget_kernel_preferred_work_group_size_multiple: + if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) + return ExprError(); } // Since the target specific builtins for each arch overlap, only check those @@ -843,7 +1343,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, return true; } - if (IsLdrex) { TheCall->setType(ValType); return false; @@ -931,7 +1430,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, false); + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || @@ -1091,19 +1590,58 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { } bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; + int i = 0, l = 0, u = 0; switch (BuiltinID) { - default: return false; + default: + return false; case X86::BI__builtin_cpu_supports: return SemaBuiltinCpuSupports(*this, 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_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + i = 1; l = 0; u = 1; + break; + case X86::BI_mm_prefetch: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + i = 1; l = 0; u = 3; + break; + case X86::BI__builtin_ia32_insertf32x8_mask: + case X86::BI__builtin_ia32_inserti32x8_mask: + case X86::BI__builtin_ia32_insertf64x4_mask: + case X86::BI__builtin_ia32_inserti64x4_mask: + case X86::BI__builtin_ia32_insertf64x2_256_mask: + case X86::BI__builtin_ia32_inserti64x2_256_mask: + case X86::BI__builtin_ia32_insertf32x4_256_mask: + case X86::BI__builtin_ia32_inserti32x4_256_mask: + i = 2; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_sha1rnds4: + case X86::BI__builtin_ia32_shuf_f32x4_256_mask: + case X86::BI__builtin_ia32_shuf_f64x2_256_mask: + case X86::BI__builtin_ia32_shuf_i32x4_256_mask: + case X86::BI__builtin_ia32_shuf_i64x2_256_mask: + case X86::BI__builtin_ia32_insertf64x2_512_mask: + case X86::BI__builtin_ia32_inserti64x2_512_mask: + case X86::BI__builtin_ia32_insertf32x4_mask: + case X86::BI__builtin_ia32_inserti32x4_mask: + i = 2; l = 0; u = 3; + break; case X86::BI__builtin_ia32_vpermil2pd: case X86::BI__builtin_ia32_vpermil2pd256: case X86::BI__builtin_ia32_vpermil2ps: - case X86::BI__builtin_ia32_vpermil2ps256: i = 3, l = 0; u = 3; break; + case X86::BI__builtin_ia32_vpermil2ps256: + i = 3; l = 0; u = 3; + break; case X86::BI__builtin_ia32_cmpb128_mask: case X86::BI__builtin_ia32_cmpw128_mask: case X86::BI__builtin_ia32_cmpd128_mask: @@ -1127,29 +1665,205 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_ucmpb512_mask: case X86::BI__builtin_ia32_ucmpw512_mask: case X86::BI__builtin_ia32_ucmpd512_mask: - case X86::BI__builtin_ia32_ucmpq512_mask: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_ucmpq512_mask: + case X86::BI__builtin_ia32_vpcomub: + case X86::BI__builtin_ia32_vpcomuw: + case X86::BI__builtin_ia32_vpcomud: + case X86::BI__builtin_ia32_vpcomuq: + case X86::BI__builtin_ia32_vpcomb: + case X86::BI__builtin_ia32_vpcomw: + case X86::BI__builtin_ia32_vpcomd: + case X86::BI__builtin_ia32_vpcomq: + i = 2; l = 0; u = 7; + break; case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: - case X86::BI__builtin_ia32_roundpd256: i = 1, l = 0; u = 15; break; + case X86::BI__builtin_ia32_roundpd256: + i = 1; l = 0; u = 15; + break; case X86::BI__builtin_ia32_roundss: - case X86::BI__builtin_ia32_roundsd: i = 2, l = 0; u = 15; break; + case X86::BI__builtin_ia32_roundsd: + case X86::BI__builtin_ia32_rangepd128_mask: + case X86::BI__builtin_ia32_rangepd256_mask: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps128_mask: + case X86::BI__builtin_ia32_rangeps256_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + i = 2; l = 0; u = 15; + break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: case X86::BI__builtin_ia32_cmpsd: case X86::BI__builtin_ia32_cmpps256: case X86::BI__builtin_ia32_cmppd256: + case X86::BI__builtin_ia32_cmpps128_mask: + case X86::BI__builtin_ia32_cmppd128_mask: + case X86::BI__builtin_ia32_cmpps256_mask: + case X86::BI__builtin_ia32_cmppd256_mask: case X86::BI__builtin_ia32_cmpps512_mask: - case X86::BI__builtin_ia32_cmppd512_mask: i = 2; l = 0; u = 31; break; - case X86::BI__builtin_ia32_vpcomub: - case X86::BI__builtin_ia32_vpcomuw: - case X86::BI__builtin_ia32_vpcomud: - case X86::BI__builtin_ia32_vpcomuq: - case X86::BI__builtin_ia32_vpcomb: - case X86::BI__builtin_ia32_vpcomw: - case X86::BI__builtin_ia32_vpcomd: - case X86::BI__builtin_ia32_vpcomq: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + i = 2; l = 0; u = 31; + break; + case X86::BI__builtin_ia32_xabort: + i = 0; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_pshufw: + case X86::BI__builtin_ia32_aeskeygenassist128: + i = 1; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_vcvtps2ph: + case X86::BI__builtin_ia32_vcvtps2ph256: + case X86::BI__builtin_ia32_rndscaleps_128_mask: + case X86::BI__builtin_ia32_rndscalepd_128_mask: + case X86::BI__builtin_ia32_rndscaleps_256_mask: + case X86::BI__builtin_ia32_rndscalepd_256_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_reducepd128_mask: + case X86::BI__builtin_ia32_reducepd256_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps128_mask: + case X86::BI__builtin_ia32_reduceps256_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_prold512_mask: + case X86::BI__builtin_ia32_prolq512_mask: + case X86::BI__builtin_ia32_prold128_mask: + case X86::BI__builtin_ia32_prold256_mask: + case X86::BI__builtin_ia32_prolq128_mask: + case X86::BI__builtin_ia32_prolq256_mask: + case X86::BI__builtin_ia32_prord128_mask: + case X86::BI__builtin_ia32_prord256_mask: + case X86::BI__builtin_ia32_prorq128_mask: + case X86::BI__builtin_ia32_prorq256_mask: + case X86::BI__builtin_ia32_psllwi512_mask: + case X86::BI__builtin_ia32_psllwi128_mask: + case X86::BI__builtin_ia32_psllwi256_mask: + case X86::BI__builtin_ia32_psrldi128_mask: + case X86::BI__builtin_ia32_psrldi256_mask: + case X86::BI__builtin_ia32_psrldi512_mask: + case X86::BI__builtin_ia32_psrlqi128_mask: + case X86::BI__builtin_ia32_psrlqi256_mask: + case X86::BI__builtin_ia32_psrlqi512_mask: + case X86::BI__builtin_ia32_psrawi512_mask: + case X86::BI__builtin_ia32_psrawi128_mask: + case X86::BI__builtin_ia32_psrawi256_mask: + case X86::BI__builtin_ia32_psrlwi512_mask: + case X86::BI__builtin_ia32_psrlwi128_mask: + case X86::BI__builtin_ia32_psrlwi256_mask: + case X86::BI__builtin_ia32_psradi128_mask: + case X86::BI__builtin_ia32_psradi256_mask: + case X86::BI__builtin_ia32_psradi512_mask: + case X86::BI__builtin_ia32_psraqi128_mask: + case X86::BI__builtin_ia32_psraqi256_mask: + case X86::BI__builtin_ia32_psraqi512_mask: + case X86::BI__builtin_ia32_pslldi128_mask: + case X86::BI__builtin_ia32_pslldi256_mask: + case X86::BI__builtin_ia32_pslldi512_mask: + case X86::BI__builtin_ia32_psllqi128_mask: + case X86::BI__builtin_ia32_psllqi256_mask: + case X86::BI__builtin_ia32_psllqi512_mask: + case X86::BI__builtin_ia32_fpclasspd128_mask: + case X86::BI__builtin_ia32_fpclasspd256_mask: + case X86::BI__builtin_ia32_fpclassps128_mask: + case X86::BI__builtin_ia32_fpclassps256_mask: + case X86::BI__builtin_ia32_fpclassps512_mask: + case X86::BI__builtin_ia32_fpclasspd512_mask: + case X86::BI__builtin_ia32_fpclasssd_mask: + case X86::BI__builtin_ia32_fpclassss_mask: + i = 1; l = 0; u = 255; + break; + case X86::BI__builtin_ia32_palignr: + case X86::BI__builtin_ia32_insertps128: + case X86::BI__builtin_ia32_dpps: + case X86::BI__builtin_ia32_dppd: + case X86::BI__builtin_ia32_dpps256: + case X86::BI__builtin_ia32_mpsadbw128: + case X86::BI__builtin_ia32_mpsadbw256: + case X86::BI__builtin_ia32_pcmpistrm128: + case X86::BI__builtin_ia32_pcmpistri128: + case X86::BI__builtin_ia32_pcmpistria128: + case X86::BI__builtin_ia32_pcmpistric128: + case X86::BI__builtin_ia32_pcmpistrio128: + case X86::BI__builtin_ia32_pcmpistris128: + case X86::BI__builtin_ia32_pcmpistriz128: + case X86::BI__builtin_ia32_pclmulqdq128: + case X86::BI__builtin_ia32_vperm2f128_pd256: + case X86::BI__builtin_ia32_vperm2f128_ps256: + case X86::BI__builtin_ia32_vperm2f128_si256: + case X86::BI__builtin_ia32_permti256: + i = 2; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_palignr128: + case X86::BI__builtin_ia32_palignr256: + case X86::BI__builtin_ia32_palignr128_mask: + case X86::BI__builtin_ia32_palignr256_mask: + case X86::BI__builtin_ia32_palignr512_mask: + case X86::BI__builtin_ia32_alignq512_mask: + case X86::BI__builtin_ia32_alignd512_mask: + case X86::BI__builtin_ia32_alignd128_mask: + case X86::BI__builtin_ia32_alignd256_mask: + case X86::BI__builtin_ia32_alignq128_mask: + case X86::BI__builtin_ia32_alignq256_mask: + case X86::BI__builtin_ia32_vcomisd: + case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_shuf_f32x4_mask: + case X86::BI__builtin_ia32_shuf_f64x2_mask: + case X86::BI__builtin_ia32_shuf_i32x4_mask: + case X86::BI__builtin_ia32_shuf_i64x2_mask: + case X86::BI__builtin_ia32_dbpsadbw128_mask: + case X86::BI__builtin_ia32_dbpsadbw256_mask: + case X86::BI__builtin_ia32_dbpsadbw512_mask: + i = 2; l = 0; u = 255; + break; + case X86::BI__builtin_ia32_fixupimmpd512_mask: + case X86::BI__builtin_ia32_fixupimmpd512_maskz: + case X86::BI__builtin_ia32_fixupimmps512_mask: + case X86::BI__builtin_ia32_fixupimmps512_maskz: + case X86::BI__builtin_ia32_fixupimmsd_mask: + case X86::BI__builtin_ia32_fixupimmsd_maskz: + case X86::BI__builtin_ia32_fixupimmss_mask: + case X86::BI__builtin_ia32_fixupimmss_maskz: + case X86::BI__builtin_ia32_fixupimmpd128_mask: + case X86::BI__builtin_ia32_fixupimmpd128_maskz: + case X86::BI__builtin_ia32_fixupimmpd256_mask: + case X86::BI__builtin_ia32_fixupimmpd256_maskz: + case X86::BI__builtin_ia32_fixupimmps128_mask: + case X86::BI__builtin_ia32_fixupimmps128_maskz: + case X86::BI__builtin_ia32_fixupimmps256_mask: + case X86::BI__builtin_ia32_fixupimmps256_maskz: + case X86::BI__builtin_ia32_pternlogd512_mask: + case X86::BI__builtin_ia32_pternlogd512_maskz: + case X86::BI__builtin_ia32_pternlogq512_mask: + case X86::BI__builtin_ia32_pternlogq512_maskz: + case X86::BI__builtin_ia32_pternlogd128_mask: + case X86::BI__builtin_ia32_pternlogd128_maskz: + case X86::BI__builtin_ia32_pternlogd256_mask: + case X86::BI__builtin_ia32_pternlogd256_maskz: + case X86::BI__builtin_ia32_pternlogq128_mask: + case X86::BI__builtin_ia32_pternlogq128_maskz: + case X86::BI__builtin_ia32_pternlogq256_mask: + case X86::BI__builtin_ia32_pternlogq256_maskz: + i = 3; l = 0; u = 255; + break; + case X86::BI__builtin_ia32_pcmpestrm128: + case X86::BI__builtin_ia32_pcmpestri128: + case X86::BI__builtin_ia32_pcmpestria128: + case X86::BI__builtin_ia32_pcmpestric128: + case X86::BI__builtin_ia32_pcmpestrio128: + case X86::BI__builtin_ia32_pcmpestris128: + case X86::BI__builtin_ia32_pcmpestriz128: + i = 4; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + i = 4; l = 0; u = 255; + break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -1534,10 +2248,10 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { } static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { - if (Ordering < AtomicExpr::AO_ABI_memory_order_relaxed || - Ordering > AtomicExpr::AO_ABI_memory_order_seq_cst) + if (!llvm::isValidAtomicOrderingCABI(Ordering)) return false; + auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering; switch (Op) { case AtomicExpr::AO__c11_atomic_init: llvm_unreachable("There is no ordering argument for an init"); @@ -1545,15 +2259,15 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: - return Ordering != AtomicExpr::AO_ABI_memory_order_release && - Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel; + return OrderingCABI != llvm::AtomicOrderingCABI::release && + OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: - return Ordering != AtomicExpr::AO_ABI_memory_order_consume && - Ordering != AtomicExpr::AO_ABI_memory_order_acquire && - Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel; + return OrderingCABI != llvm::AtomicOrderingCABI::consume && + OrderingCABI != llvm::AtomicOrderingCABI::acquire && + OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; default: return true; @@ -1572,6 +2286,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // C __c11_atomic_load(A *, int) Load, // void __atomic_load(A *, CP, int) + LoadCopy, + // void __atomic_store(A *, CP, int) Copy, // C __c11_atomic_add(A *, M, int) Arithmetic, @@ -1584,8 +2300,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) GNUCmpXchg } Form = Init; - const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 4, 5, 6 }; - const unsigned NumVals[] = { 1, 0, 1, 1, 1, 2, 2, 3 }; + const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; + const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: // C is an appropriate type, // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, @@ -1615,8 +2331,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Form = Load; break; - case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_load: + Form = LoadCopy; + break; + + case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; @@ -1680,7 +2399,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // Inspect the first argument of the atomic operation. Expr *Ptr = TheCall->getArg(0); - Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get(); + ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); + if (ConvertedPtr.isInvalid()) + return ExprError(); + + Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) @@ -1703,7 +2426,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } ValType = AtomTy->getAs<AtomicType>()->getValueType(); - } else if (Form != Load && Op != AtomicExpr::AO__atomic_load) { + } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); @@ -1764,10 +2487,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the // volatile-ness of the pointee-type inject itself into the result or the - // other operands. + // other operands. Similarly atomic_load can take a pointer to a const 'A'. ValType.removeLocalVolatile(); + ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == GNUXchg || Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; @@ -1778,10 +2502,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (!IsC11 && !IsN) ByValType = Ptr->getType(); - // FIXME: __atomic_load allows the first argument to be a a pointer to const - // but not the second argument. We need to manually remove possible const - // qualifiers. - // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. @@ -1848,6 +2568,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case Load: SubExprs.push_back(TheCall->getArg(1)); // Order break; + case LoadCopy: case Copy: case Arithmetic: case Xchg: @@ -1897,7 +2618,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return AE; } - /// checkBuiltinArgument - Given a call to a builtin function, perform /// normal type-checking on the given argument, updating the call in /// place. This is useful when a builtin function requires custom @@ -2443,6 +3163,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { // block. QualType Type; SourceLocation ParamLoc; + bool IsCRegister = false; if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { @@ -2450,24 +3171,30 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { // Get the last formal in the current function. const ParmVarDecl *LastArg; if (CurBlock) - LastArg = *(CurBlock->TheDecl->param_end()-1); + LastArg = CurBlock->TheDecl->parameters().back(); else if (FunctionDecl *FD = getCurFunctionDecl()) - LastArg = *(FD->param_end()-1); + LastArg = FD->parameters().back(); else - LastArg = *(getCurMethodDecl()->param_end()-1); + LastArg = getCurMethodDecl()->parameters().back(); SecondArgIsLastNamedArgument = PV == LastArg; Type = PV->getType(); ParamLoc = PV->getLocation(); + IsCRegister = + PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; } } if (!SecondArgIsLastNamedArgument) Diag(TheCall->getArg(1)->getLocStart(), - diag::warn_second_parameter_of_va_start_not_last_named_argument); - else if (Type->isReferenceType()) { - Diag(Arg->getLocStart(), - diag::warn_va_start_of_reference_type_is_undefined); + diag::warn_second_arg_of_va_start_not_last_named_param); + else if (IsCRegister || Type->isReferenceType() || + Type->isPromotableIntegerType() || + Type->isSpecificBuiltinType(BuiltinType::Float)) { + 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; } @@ -2662,8 +3389,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // Determine which of the following types of shufflevector we're checking: // 1) unary, vector mask: (lhs, mask) - // 2) binary, vector mask: (lhs, rhs, mask) - // 3) binary, scalar mask: (lhs, rhs, index, ..., index) + // 2) binary, scalar mask: (lhs, rhs, index, ..., index) QualType resType = TheCall->getArg(0)->getType(); unsigned numElements = 0; @@ -3002,7 +3728,6 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } - /// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). /// This checks that the target supports __builtin_setjmp. bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { @@ -3013,12 +3738,68 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { } namespace { +class UncoveredArgHandler { + enum { Unknown = -1, AllCovered = -2 }; + signed FirstUncoveredArg; + SmallVector<const Expr *, 4> DiagnosticExprs; + +public: + UncoveredArgHandler() : FirstUncoveredArg(Unknown) { } + + bool hasUncoveredArg() const { + return (FirstUncoveredArg >= 0); + } + + unsigned getUncoveredArg() const { + assert(hasUncoveredArg() && "no uncovered argument"); + return FirstUncoveredArg; + } + + void setAllCovered() { + // A string has been found with all arguments covered, so clear out + // the diagnostics. + DiagnosticExprs.clear(); + FirstUncoveredArg = AllCovered; + } + + void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) { + assert(NewFirstUncoveredArg >= 0 && "Outside range"); + + // Don't update if a previous string covers all arguments. + if (FirstUncoveredArg == AllCovered) + return; + + // UncoveredArgHandler tracks the highest uncovered argument index + // and with it all the strings that match this index. + if (NewFirstUncoveredArg == FirstUncoveredArg) + DiagnosticExprs.push_back(StrExpr); + else if (NewFirstUncoveredArg > FirstUncoveredArg) { + DiagnosticExprs.clear(); + DiagnosticExprs.push_back(StrExpr); + FirstUncoveredArg = NewFirstUncoveredArg; + } + } + + void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr); +}; + enum StringLiteralCheckType { SLCT_NotALiteral, SLCT_UncheckedLiteral, SLCT_CheckedLiteral }; -} +} // end anonymous namespace + +static void CheckFormatString(Sema &S, const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, + Sema::FormatStringType Type, + bool inFunctionCall, + Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a @@ -3029,7 +3810,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, - llvm::SmallBitVector &CheckedVarArgs) { + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) { tryAgain: if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; @@ -3050,17 +3832,39 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, // completely checked only if both sub-expressions were checked. const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E); - StringLiteralCheckType Left = - checkFormatStringExpr(S, C->getTrueExpr(), Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs); - if (Left == SLCT_NotALiteral) - return SLCT_NotALiteral; + + // Determine whether it is necessary to check both sub-expressions, for + // example, because the condition expression is a constant that can be + // evaluated at compile time. + bool CheckLeft = true, CheckRight = true; + + bool Cond; + if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) { + if (Cond) + CheckRight = false; + else + CheckLeft = false; + } + + StringLiteralCheckType Left; + if (!CheckLeft) + Left = SLCT_UncheckedLiteral; + else { + Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, + HasVAListArg, format_idx, firstDataArg, + Type, CallType, InFunctionCall, + CheckedVarArgs, UncoveredArg); + if (Left == SLCT_NotALiteral || !CheckRight) + return Left; + } + StringLiteralCheckType Right = checkFormatStringExpr(S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs); - return Left < Right ? Left : Right; + Type, CallType, InFunctionCall, CheckedVarArgs, + UncoveredArg); + + return (CheckLeft && Left < Right) ? Left : Right; } case Stmt::ImplicitCastExprClass: { @@ -3111,7 +3915,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Init, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*InFunctionCall*/false, CheckedVarArgs); + /*InFunctionCall*/false, CheckedVarArgs, + UncoveredArg); } } @@ -3166,7 +3971,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs); + CheckedVarArgs, UncoveredArg); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || @@ -3175,7 +3980,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - InFunctionCall, CheckedVarArgs); + InFunctionCall, CheckedVarArgs, + UncoveredArg); } } } @@ -3192,8 +3998,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, StrE = cast<StringLiteral>(E); if (StrE) { - S.CheckFormatString(StrE, E, Args, HasVAListArg, format_idx, firstDataArg, - Type, InFunctionCall, CallType, CheckedVarArgs); + CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx, + firstDataArg, Type, InFunctionCall, CallType, + CheckedVarArgs, UncoveredArg); return SLCT_CheckedLiteral; } @@ -3261,10 +4068,20 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, // C string (e.g. "%d") // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. + UncoveredArgHandler UncoveredArg; StringLiteralCheckType CT = checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*IsFunctionCall*/true, CheckedVarArgs); + /*IsFunctionCall*/true, CheckedVarArgs, + UncoveredArg); + + // Generate a diagnostic where an uncovered argument is detected. + if (UncoveredArg.hasUncoveredArg()) { + unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg; + assert(ArgIdx < Args.size() && "ArgIdx outside bounds"); + UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]); + } + if (CT != SLCT_NotALiteral) // Literal format string found, check done! return CT == SLCT_CheckedLiteral; @@ -3278,20 +4095,33 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, // format is either NSString or CFString. This is a hack to prevent // diag when using the NSLocalizedString and CFCopyLocalizedString macros // which are usually used in place of NS and CF string literals. - if (Type == FST_NSString && - SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart())) + SourceLocation FormatLoc = Args[format_idx]->getLocStart(); + if (Type == FST_NSString && SourceMgr.isInSystemMacro(FormatLoc)) return false; // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. - if (Args.size() == firstDataArg) - Diag(Args[format_idx]->getLocStart(), - diag::warn_format_nonliteral_noargs) + if (Args.size() == firstDataArg) { + Diag(FormatLoc, diag::warn_format_nonliteral_noargs) << OrigFormatExpr->getSourceRange(); - else - Diag(Args[format_idx]->getLocStart(), - diag::warn_format_nonliteral) - << OrigFormatExpr->getSourceRange(); + switch (Type) { + default: + break; + case FST_Kprintf: + case FST_FreeBSDKPrintf: + case FST_Printf: + Diag(FormatLoc, diag::note_format_security_fixit) + << FixItHint::CreateInsertion(FormatLoc, "\"%s\", "); + break; + case FST_NSString: + Diag(FormatLoc, diag::note_format_security_fixit) + << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", "); + break; + } + } else { + Diag(FormatLoc, diag::warn_format_nonliteral) + << OrigFormatExpr->getSourceRange(); + } return false; } @@ -3313,6 +4143,8 @@ protected: bool inFunctionCall; Sema::VariadicCallType CallType; llvm::SmallBitVector &CheckedVarArgs; + UncoveredArgHandler &UncoveredArg; + public: CheckFormatHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, @@ -3320,14 +4152,15 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType callType, - llvm::SmallBitVector &CheckedVarArgs) + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), usesPositionalArgs(false), atFirstArg(true), inFunctionCall(inFunctionCall), CallType(callType), - CheckedVarArgs(CheckedVarArgs) { + CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } @@ -3362,12 +4195,11 @@ public: void HandleNullChar(const char *nullCharacter) override; template <typename Range> - static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall, - const Expr *ArgumentExpr, - PartialDiagnostic PDiag, - SourceLocation StringLoc, - bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = None); + static void + EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, + const PartialDiagnostic &PDiag, SourceLocation StringLoc, + bool IsStringLocation, Range StringRange, + ArrayRef<FixItHint> Fixit = None); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -3396,7 +4228,7 @@ protected: bool IsStringLocation, Range StringRange, ArrayRef<FixItHint> Fixit = None); }; -} +} // end anonymous namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); @@ -3558,26 +4390,44 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const { } void CheckFormatHandler::DoneProcessing() { - // Does the number of data arguments exceed the number of - // format conversions in the format string? + // Does the number of data arguments exceed the number of + // format conversions in the format string? if (!HasVAListArg) { // Find any arguments that weren't covered. CoveredArgs.flip(); signed notCoveredArg = CoveredArgs.find_first(); if (notCoveredArg >= 0) { assert((unsigned)notCoveredArg < NumDataArgs); - if (const Expr *E = getDataArg((unsigned) notCoveredArg)) { - SourceLocation Loc = E->getLocStart(); - if (!S.getSourceManager().isInSystemMacro(Loc)) { - EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used), - Loc, /*IsStringLocation*/false, - getFormatStringRange()); - } - } + UncoveredArg.Update(notCoveredArg, OrigFormatExpr); + } else { + UncoveredArg.setAllCovered(); } } } +void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, + const Expr *ArgExpr) { + assert(hasUncoveredArg() && DiagnosticExprs.size() > 0 && + "Invalid state"); + + if (!ArgExpr) + return; + + SourceLocation Loc = ArgExpr->getLocStart(); + + if (S.getSourceManager().isInSystemMacro(Loc)) + return; + + PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used); + for (auto E : DiagnosticExprs) + PDiag << E->getSourceRange(); + + CheckFormatHandler::EmitFormatDiagnostic( + S, IsFunctionCall, DiagnosticExprs[0], + PDiag, Loc, /*IsStringLocation*/false, + DiagnosticExprs[0]->getSourceRange()); +} + bool CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -3585,7 +4435,6 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, unsigned specifierLen, const char *csStart, unsigned csLen) { - bool keepGoing = true; if (argIndex < NumDataArgs) { // Consider the argument coverered, even though the specifier doesn't @@ -3600,12 +4449,41 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, // gibberish when trying to match arguments. keepGoing = false; } - - EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_conversion) - << StringRef(csStart, csLen), - Loc, /*IsStringLocation*/true, - getSpecifierRange(startSpec, specifierLen)); - + + StringRef Specifier(csStart, csLen); + + // If the specifier in non-printable, it could be the first byte of a UTF-8 + // sequence. In that case, print the UTF-8 code point. If not, print the byte + // hex value. + std::string CodePointStr; + if (!llvm::sys::locale::isPrint(*csStart)) { + UTF32 CodePoint; + const UTF8 **B = reinterpret_cast<const UTF8 **>(&csStart); + const UTF8 *E = + reinterpret_cast<const UTF8 *>(csStart + csLen); + ConversionResult Result = + llvm::convertUTF8Sequence(B, E, &CodePoint, strictConversion); + + if (Result != conversionOK) { + unsigned char FirstChar = *csStart; + CodePoint = (UTF32)FirstChar; + } + + llvm::raw_string_ostream OS(CodePointStr); + if (CodePoint < 256) + OS << "\\x" << llvm::format("%02x", CodePoint); + else if (CodePoint <= 0xFFFF) + OS << "\\u" << llvm::format("%04x", CodePoint); + else + OS << "\\U" << llvm::format("%08x", CodePoint); + OS.flush(); + Specifier = CodePointStr; + } + + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc, + /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen)); + return keepGoing; } @@ -3632,6 +4510,10 @@ CheckFormatHandler::CheckNumArgs( EmitFormatDiagnostic( PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); + + // Since more arguments than conversion tokens are given, by extension + // all arguments are covered, so mark this as so. + UncoveredArg.setAllCovered(); return false; } return true; @@ -3674,14 +4556,11 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, /// templated so it can accept either a CharSourceRange or a SourceRange. /// /// \param FixIt optional fix it hint for the format string. -template<typename Range> -void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, - const Expr *ArgumentExpr, - PartialDiagnostic PDiag, - SourceLocation Loc, - bool IsStringLocation, - Range StringRange, - ArrayRef<FixItHint> FixIt) { +template <typename Range> +void CheckFormatHandler::EmitFormatDiagnostic( + Sema &S, bool InFunctionCall, const Expr *ArgumentExpr, + const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation, + Range StringRange, ArrayRef<FixItHint> FixIt) { if (InFunctionCall) { const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); D << StringRange; @@ -3704,6 +4583,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, namespace { class CheckPrintfHandler : public CheckFormatHandler { bool ObjCContext; + public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, @@ -3712,14 +4592,15 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, - formatIdx, inFunctionCall, CallType, CheckedVarArgs), + formatIdx, inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg), ObjCContext(isObjC) {} - bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, @@ -3760,7 +4641,7 @@ public: const char *conversionPosition) override; }; -} +} // end anonymous namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -3779,7 +4660,6 @@ bool CheckPrintfHandler::HandleAmount( const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen) { - if (Amt.hasDataArgument()) { if (!HasVAListArg) { unsigned argIndex = Amt.getArgIndex(); @@ -3991,7 +4871,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - using namespace analyze_format_string; using namespace analyze_printf; const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -4361,7 +5240,6 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, E->getLocStart(), /*IsStringLocation*/ false, SpecRange, FixItHint::CreateReplacement(SpecRange, os.str())); - } else { // The canonical type for formatting this value is different from the // actual type of the expression. (This occurs, for example, with Darwin's @@ -4500,11 +5378,12 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, formatIdx, inFunctionCall, CallType, - CheckedVarArgs) + CheckedVarArgs, UncoveredArg) {} bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, @@ -4518,7 +5397,7 @@ public: void HandleIncompleteScanList(const char *start, const char *end) override; }; -} +} // end anonymous namespace void CheckScanfHandler::HandleIncompleteScanList(const char *start, const char *end) { @@ -4545,7 +5424,6 @@ bool CheckScanfHandler::HandleScanfSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - using namespace analyze_scanf; using namespace analyze_format_string; @@ -4665,28 +5543,31 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } -void Sema::CheckFormatString(const StringLiteral *FExpr, - const Expr *OrigFormatExpr, - ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg, FormatStringType Type, - bool inFunctionCall, VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) { - +static void CheckFormatString(Sema &S, const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, + Sema::FormatStringType Type, + bool inFunctionCall, + Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } - + // Str - The format string. NOTE: this is NOT null-terminated! StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); // Account for cases where the string literal is truncated in a declaration. - const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); + const ConstantArrayType *T = + S.Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); size_t TypeSize = T->getSize().getZExtValue(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); @@ -4697,8 +5578,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, if (TypeSize <= StrRef.size() && StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_printf_format_string_not_null_terminated), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_printf_format_string_not_null_terminated), FExpr->getLocStart(), /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange()); return; @@ -4707,32 +5588,35 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, // CHECK: empty format string? if (StrLen == 0 && numDataArgs > 0) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_empty_format_string), FExpr->getLocStart(), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_empty_format_string), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } - - if (Type == FST_Printf || Type == FST_NSString || - Type == FST_FreeBSDKPrintf || Type == FST_OSTrace) { - CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - numDataArgs, (Type == FST_NSString || Type == FST_OSTrace), + + if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || + Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) { + CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, + numDataArgs, (Type == Sema::FST_NSString || + Type == Sema::FST_OSTrace), Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs); - + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); + if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, - getLangOpts(), - Context.getTargetInfo(), - Type == FST_FreeBSDKPrintf)) + S.getLangOpts(), + S.Context.getTargetInfo(), + Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); - } else if (Type == FST_Scanf) { - CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, + } else if (Type == Sema::FST_Scanf) { + CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs); - + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); + if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, - getLangOpts(), - Context.getTargetInfo())) + S.getLangOpts(), + S.Context.getTargetInfo())) H.DoneProcessing(); } // TODO: handle other formats } @@ -5145,7 +6029,6 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, emitReplacement(*this, Call->getExprLoc(), Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); - return; } //===--- CHECK: Standard memory functions ---------------------------------===// @@ -5191,7 +6074,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); RD = RD ? RD->getDefinition() : nullptr; - if (!RD) + if (!RD || RD->isInvalidDecl()) return nullptr; if (RD->isDynamicClass()) @@ -5398,7 +6281,6 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); break; } - } // A little helper routine: ignore addition and subtraction of integer literals. @@ -5613,10 +6495,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, //===--- CHECK: Return Address of Stack Variable --------------------------===// -static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl); -static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl); +static const Expr *EvalVal(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl); +static const Expr *EvalAddr(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -5624,8 +6508,8 @@ static void CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { - Expr *stackE = nullptr; - SmallVector<DeclRefExpr *, 8> refVars; + const Expr *stackE = nullptr; + SmallVector<const DeclRefExpr *, 8> refVars; // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. @@ -5653,7 +6537,8 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, diagRange = refVars[0]->getSourceRange(); } - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { + // address of local var S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() << DR->getDecl()->getDeclName() << diagRange; } else if (isa<BlockExpr>(stackE)) { // local block. @@ -5668,12 +6553,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, // Display the "trail" of reference variables that we followed until we // found the problematic expression using notes. for (unsigned i = 0, e = refVars.size(); i != e; ++i) { - VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); + const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); // If this var binds to another reference var, show the range of the next // var, otherwise the var binds to the problematic expression, in which case // show the range of the expression. - SourceRange range = (i < e-1) ? refVars[i+1]->getSourceRange() - : stackE->getSourceRange(); + SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() + : stackE->getSourceRange(); S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) << VD->getDeclName() << range; } @@ -5705,8 +6590,9 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl) { +static const Expr *EvalAddr(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl) { if (E->isTypeDependent()) return nullptr; @@ -5723,13 +6609,13 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: { - DeclRefExpr *DR = cast<DeclRefExpr>(E); + const DeclRefExpr *DR = cast<DeclRefExpr>(E); // If we leave the immediate function, the lifetime isn't about to end. if (DR->refersToEnclosingVariableOrCapture()) return nullptr; - if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) + if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) // If this is a reference variable, follow through to the expression that // it points to. if (V->hasLocalStorage() && @@ -5745,44 +6631,44 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is AddrOf. All others don't make sense as pointers. - UnaryOperator *U = cast<UnaryOperator>(E); + const UnaryOperator *U = cast<UnaryOperator>(E); if (U->getOpcode() == UO_AddrOf) return EvalVal(U->getSubExpr(), refVars, ParentDecl); - else - return nullptr; + return nullptr; } case Stmt::BinaryOperatorClass: { // Handle pointer arithmetic. All other binary operators are not valid // in this context. - BinaryOperator *B = cast<BinaryOperator>(E); + const BinaryOperator *B = cast<BinaryOperator>(E); BinaryOperatorKind op = B->getOpcode(); if (op != BO_Add && op != BO_Sub) return nullptr; - Expr *Base = B->getLHS(); + const Expr *Base = B->getLHS(); // Determine which argument is the real pointer base. It could be // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) Base = B->getRHS(); + if (!Base->getType()->isPointerType()) + Base = B->getRHS(); - assert (Base->getType()->isPointerType()); + assert(Base->getType()->isPointerType()); return EvalAddr(Base, refVars, ParentDecl); } // For conditional operators we need to see if either the LHS or RHS are // valid DeclRefExpr*s. If one of them is valid, we return it. case Stmt::ConditionalOperatorClass: { - ConditionalOperator *C = cast<ConditionalOperator>(E); + const ConditionalOperator *C = cast<ConditionalOperator>(E); // Handle the GNU extension for missing LHS. // FIXME: That isn't a ConditionalOperator, so doesn't get here. - if (Expr *LHSExpr = C->getLHS()) { + if (const Expr *LHSExpr = C->getLHS()) { // In C++, we can have a throw-expression, which has 'void' type. if (!LHSExpr->getType()->isVoidType()) - if (Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) + if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) return LHS; } @@ -5815,7 +6701,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, case Stmt::CXXDynamicCastExprClass: case Stmt::CXXConstCastExprClass: case Stmt::CXXReinterpretCastExprClass: { - Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); + const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); switch (cast<CastExpr>(E)->getCastKind()) { case CK_LValueToRValue: case CK_NoOp: @@ -5845,157 +6731,161 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, } case Stmt::MaterializeTemporaryExprClass: - if (Expr *Result = EvalAddr( - cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) + if (const Expr *Result = + EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars, ParentDecl)) return Result; - return E; - + // Everything else: we simply don't reason about them. default: return nullptr; } } - /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl) { -do { - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - - E = E->IgnoreParens(); - switch (E->getStmtClass()) { - case Stmt::ImplicitCastExprClass: { - ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); - if (IE->getValueKind() == VK_LValue) { - E = IE->getSubExpr(); - continue; +static const Expr *EvalVal(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl) { + do { + // We should only be called for evaluating non-pointer expressions, or + // expressions with a pointer type that are not used as references but + // instead + // are l-values (e.g., DeclRefExpr with a pointer type). + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + + E = E->IgnoreParens(); + switch (E->getStmtClass()) { + case Stmt::ImplicitCastExprClass: { + const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); + if (IE->getValueKind() == VK_LValue) { + E = IE->getSubExpr(); + continue; + } + return nullptr; } - return nullptr; - } - - case Stmt::ExprWithCleanupsClass: - return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl); - case Stmt::DeclRefExprClass: { - // When we hit a DeclRefExpr we are looking at code that refers to a - // variable's name. If it's not a reference variable we check if it has - // local storage within the function, and if so, return the expression. - DeclRefExpr *DR = cast<DeclRefExpr>(E); + case Stmt::ExprWithCleanupsClass: + return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, + ParentDecl); - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; + case Stmt::DeclRefExprClass: { + // When we hit a DeclRefExpr we are looking at code that refers to a + // variable's name. If it's not a reference variable we check if it has + // local storage within the function, and if so, return the expression. + const DeclRefExpr *DR = cast<DeclRefExpr>(E); - if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { - // Check if it refers to itself, e.g. "int& i = i;". - if (V == ParentDecl) - return DR; + // If we leave the immediate function, the lifetime isn't about to end. + if (DR->refersToEnclosingVariableOrCapture()) + return nullptr; - if (V->hasLocalStorage()) { - if (!V->getType()->isReferenceType()) + if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { + // Check if it refers to itself, e.g. "int& i = i;". + if (V == ParentDecl) return DR; - // Reference variable, follow through to the expression that - // it points to. - if (V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalVal(V->getInit(), refVars, V); + if (V->hasLocalStorage()) { + if (!V->getType()->isReferenceType()) + return DR; + + // Reference variable, follow through to the expression that + // it points to. + if (V->hasInit()) { + // Add the reference variable to the "trail". + refVars.push_back(DR); + return EvalVal(V->getInit(), refVars, V); + } } } - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - UnaryOperator *U = cast<UnaryOperator>(E); - if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars, ParentDecl); + return nullptr; + } - return nullptr; - } + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + const UnaryOperator *U = cast<UnaryOperator>(E); - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl); - } + if (U->getOpcode() == UO_Deref) + return EvalAddr(U->getSubExpr(), refVars, ParentDecl); - case Stmt::OMPArraySectionExprClass: { - return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, - ParentDecl); - } + return nullptr; + } - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL Expr's. If one is non-NULL, we return it. - ConditionalOperator *C = cast<ConditionalOperator>(E); + case Stmt::ArraySubscriptExprClass: { + // Array subscripts are potential references to data on the stack. We + // retrieve the DeclRefExpr* for the array variable if it indeed + // has local storage. + const auto *ASE = cast<ArraySubscriptExpr>(E); + if (ASE->isTypeDependent()) + return nullptr; + return EvalAddr(ASE->getBase(), refVars, ParentDecl); + } - // Handle the GNU extension for missing LHS. - if (Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) - return LHS; + case Stmt::OMPArraySectionExprClass: { + return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, + ParentDecl); } - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; + case Stmt::ConditionalOperatorClass: { + // For conditional operators we need to see if either the LHS or RHS are + // non-NULL Expr's. If one is non-NULL, we return it. + const ConditionalOperator *C = cast<ConditionalOperator>(E); + + // Handle the GNU extension for missing LHS. + if (const Expr *LHSExpr = C->getLHS()) { + // In C++, we can have a throw-expression, which has 'void' type. + if (!LHSExpr->getType()->isVoidType()) + if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) + return LHS; + } - return EvalVal(C->getRHS(), refVars, ParentDecl); - } + // In C++, we can have a throw-expression, which has 'void' type. + if (C->getRHS()->getType()->isVoidType()) + return nullptr; - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - MemberExpr *M = cast<MemberExpr>(E); + return EvalVal(C->getRHS(), refVars, ParentDecl); + } - // Check for indirect access. We only want direct field accesses. - if (M->isArrow()) - return nullptr; + // Accesses to members are potential references to data on the stack. + case Stmt::MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(E); - // Check whether the member type is itself a reference, in which case - // we're not going to refer to the member, but to what the member refers to. - if (M->getMemberDecl()->getType()->isReferenceType()) - return nullptr; + // Check for indirect access. We only want direct field accesses. + if (M->isArrow()) + return nullptr; - return EvalVal(M->getBase(), refVars, ParentDecl); - } + // Check whether the member type is itself a reference, in which case + // we're not going to refer to the member, but to what the member refers + // to. + if (M->getMemberDecl()->getType()->isReferenceType()) + return nullptr; - case Stmt::MaterializeTemporaryExprClass: - if (Expr *Result = EvalVal( - cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - - return E; + return EvalVal(M->getBase(), refVars, ParentDecl); + } - default: - // Check that we don't return or take the address of a reference to a - // temporary. This is only useful in C++. - if (!E->isTypeDependent() && E->isRValue()) + case Stmt::MaterializeTemporaryExprClass: + if (const Expr *Result = + EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars, ParentDecl)) + return Result; return E; - // Everything else: we simply don't reason about them. - return nullptr; - } -} while (true); + default: + // Check that we don't return or take the address of a reference to a + // temporary. This is only useful in C++. + if (!E->isTypeDependent() && E->isRValue()) + return E; + + // Everything else: we simply don't reason about them. + return nullptr; + } + } while (true); } void @@ -6047,7 +6937,6 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { if (DRL->getDecl() == DRR->getDecl()) return; - // Special case: check for comparisons against literals that can be exactly // represented by APFloat. In such cases, do not emit a warning. This // is a heuristic: often comparison against such literals are used to @@ -6173,8 +7062,7 @@ struct IntRange { } }; -static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, - unsigned MaxWidth) { +IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) return IntRange(value.getMinSignedBits(), false); @@ -6186,8 +7074,8 @@ static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, return IntRange(value.getActiveBits(), true); } -static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, - unsigned MaxWidth) { +IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { if (result.isInt()) return GetValueRange(C, result.getInt(), MaxWidth); @@ -6215,7 +7103,7 @@ static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } -static QualType GetExprType(Expr *E) { +QualType GetExprType(const Expr *E) { QualType Ty = E->getType(); if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>()) Ty = AtomicRHS->getValueType(); @@ -6226,7 +7114,7 @@ static QualType GetExprType(Expr *E) { /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated -static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { +IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { E = E->IgnoreParens(); // Try a full evaluation first. @@ -6237,7 +7125,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // I think we only want to look through implicit casts here; if the // user has an explicit widening cast, we should treat the value as // being of the new, wider type. - if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) { + if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) { if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) return GetExprRange(C, CE->getSubExpr(), MaxWidth); @@ -6264,7 +7152,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { SubRange.NonNegative || OutputTypeRange.NonNegative); } - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { // If we can fold the condition, just take that operand. bool CondResult; if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) @@ -6278,7 +7166,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::join(L, R); } - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (const auto *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { // Boolean-valued operations are single-bit and positive. @@ -6418,7 +7306,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::join(L, R); } - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (const auto *UO = dyn_cast<UnaryOperator>(E)) { switch (UO->getOpcode()) { // Boolean-valued operations are white-listed. case UO_LNot: @@ -6434,26 +7322,26 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { } } - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) return GetExprRange(C, OVE->getSourceExpr(), MaxWidth); - if (FieldDecl *BitField = E->getSourceBitField()) + if (const auto *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); return IntRange::forValueOfType(C, GetExprType(E)); } -static IntRange GetExprRange(ASTContext &C, Expr *E) { +IntRange GetExprRange(ASTContext &C, const Expr *E) { return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. -static bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { llvm::APFloat truncated = value; bool ignored; @@ -6468,9 +7356,9 @@ static bool IsSameFloatAfterCast(const llvm::APFloat &value, /// target semantics. /// /// The value might be a vector of floats (or a complex number). -static bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { if (value.isFloat()) return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); @@ -6486,9 +7374,9 @@ static bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); -static bool IsZero(Sema &S, Expr *E) { +bool IsZero(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) @@ -6503,7 +7391,7 @@ static bool IsZero(Sema &S, Expr *E) { return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; } -static bool HasEnumType(Expr *E) { +bool HasEnumType(Expr *E) { // Strip off implicit integral promotions. while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() != CK_IntegralCast && @@ -6515,7 +7403,7 @@ static bool HasEnumType(Expr *E) { return E->getType()->isEnumeralType(); } -static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { +void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; @@ -6543,10 +7431,9 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { } } -static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, - Expr *Constant, Expr *Other, - llvm::APSInt Value, - bool RhsConstant) { +void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, + Expr *Other, const llvm::APSInt &Value, + bool RhsConstant) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; @@ -6754,7 +7641,7 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. -static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { +void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } @@ -6762,7 +7649,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings -static void AnalyzeComparison(Sema &S, BinaryOperator *E) { +void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -6863,8 +7750,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { /// Analyzes an attempt to assign the given value to a bitfield. /// /// Returns true if there was something fishy about the attempt. -static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, - SourceLocation InitLoc) { +bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, + SourceLocation InitLoc) { assert(Bitfield->isBitField()); if (Bitfield->isInvalidDecl()) return false; @@ -6918,7 +7805,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, /// Analyze the given simple or compound assignment for warning-worthy /// operations. -static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { +void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // Just recurse on the LHS. AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); @@ -6937,9 +7824,9 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, + SourceLocation CContext, unsigned diag, + bool pruneControlFlow = false) { if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) @@ -6952,25 +7839,75 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, + unsigned diag, bool pruneControlFlow = false) { DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } -/// Diagnose an implicit cast from a literal expression. Does not warn when the -/// cast wouldn't lose information. -void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, - SourceLocation CContext) { - // Try to convert the literal exactly to an integer. If we can, don't warn. + +/// Diagnose an implicit cast from a floating point value to an integer value. +void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, + + SourceLocation CContext) { + const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); + const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty(); + + Expr *InnerE = E->IgnoreParenImpCasts(); + // We also want to warn on, e.g., "int i = -1.234" + if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) + if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) + InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); + + const bool IsLiteral = + isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE); + + llvm::APFloat Value(0.0); + bool IsConstant = + E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); + if (!IsConstant) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + bool isExact = false; - const llvm::APFloat &Value = FL->getValue(); + llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, - llvm::APFloat::rmTowardZero, &isExact) - == llvm::APFloat::opOK && isExact) - return; + if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, + &isExact) == llvm::APFloat::opOK && + isExact) { + if (IsLiteral) return; + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, + PruneWarnings); + } + + unsigned DiagID = 0; + if (IsLiteral) { + // Warn on floating point literal to integer. + DiagID = diag::warn_impcast_literal_float_to_integer; + } else if (IntegerValue == 0) { + if (Value.isZero()) { // Skip -0.0 to 0 conversion. + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + // Warn on non-zero to zero conversion. + DiagID = diag::warn_impcast_float_to_integer_zero; + } else { + if (IntegerValue.isUnsigned()) { + if (!IntegerValue.isMaxValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } else { // IntegerValue.isSigned() + if (!IntegerValue.isMaxSignedValue() && + !IntegerValue.isMinSignedValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } + // Warn on evaluatable floating point expression to integer conversion. + DiagID = diag::warn_impcast_float_to_integer; + } // FIXME: Force the precision of the source value down so we don't print // digits which are usually useless (we don't really care here if we @@ -6983,14 +7920,22 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, Value.toString(PrettySourceValue, precision); SmallString<16> PrettyTargetValue; - if (T->isSpecificBuiltinType(BuiltinType::Bool)) + if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; else IntegerValue.toString(PrettyTargetValue); - S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) - << FL->getType() << T.getUnqualifiedType() << PrettySourceValue - << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext); + if (PruneWarnings) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(DiagID) + << E->getType() << T.getUnqualifiedType() + << PrettySourceValue << PrettyTargetValue + << E->getSourceRange() << SourceRange(CContext)); + } else { + S.Diag(E->getExprLoc(), DiagID) + << E->getType() << T.getUnqualifiedType() << PrettySourceValue + << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext); + } } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -7002,7 +7947,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } -static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { +bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { if (!isa<ImplicitCastExpr>(Ex)) return false; @@ -7042,8 +7987,7 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, } } -static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC) { +void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, E->getExprLoc())) return; @@ -7065,14 +8009,21 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation Loc = E->getSourceRange().getBegin(); + // Venture through the macro stacks to get to the source of macro arguments. + // The new location is a better location than the complete location that was + // passed in. + while (S.SourceMgr.isMacroArgExpansion(Loc)) + Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); + + while (S.SourceMgr.isMacroArgExpansion(CC)) + CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); + // __null is usually wrapped in a macro. Go up a macro if that is the case. - if (NullKind == Expr::NPCK_GNUNull) { - if (Loc.isMacroID()) { - StringRef MacroName = - Lexer::getImmediateMacroName(Loc, S.SourceMgr, S.getLangOpts()); - if (MacroName == "NULL") - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; - } + if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { + StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( + Loc, S.SourceMgr, S.getLangOpts()); + if (MacroName == "NULL") + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; } // Only warn if the null and context location are in the same macro expansion. @@ -7085,17 +8036,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, S.getFixItZeroLiteralForType(T, Loc)); } -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral); -static void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral); +void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); +void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); /// Check a single element within a collection literal against the /// target element type. -static void checkObjCCollectionLiteralElement(Sema &S, - QualType TargetElementType, - Expr *Element, - unsigned ElementKind) { +void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, + Expr *Element, unsigned ElementKind) { // Skip a bitcast to 'id' or qualified 'id'. if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { if (ICE->getCastKind() == CK_BitCast && @@ -7124,8 +8073,8 @@ static void checkObjCCollectionLiteralElement(Sema &S, /// Check an Objective-C array literal being converted to the given /// target type. -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral) { +void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { if (!S.NSArrayDecl) return; @@ -7152,9 +8101,8 @@ static void checkObjCArrayLiteral(Sema &S, QualType TargetType, /// Check an Objective-C dictionary literal being converted to the given /// target type. -static void checkObjCDictionaryLiteral( - Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral) { +void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { if (!S.NSDictionaryDecl) return; @@ -7180,6 +8128,32 @@ static void checkObjCDictionaryLiteral( } } +// Helper function to filter out cases for constant width constant conversion. +// Don't warn on char array initialization or for non-decimal values. +bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { + // If initializing from a constant, and the constant starts with '0', + // then it is a binary, octal, or hexadecimal. Allow these constants + // to fill all the bits, even if there is a sign change. + if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) { + const char FirstLiteralCharacter = + S.getSourceManager().getCharacterData(IntLit->getLocStart())[0]; + if (FirstLiteralCharacter == '0') + return false; + } + + // If the CC location points to a '{', and the type is char, then assume + // assume it is an array initialization. + if (CC.isValid() && T->isCharType()) { + const char FirstContextCharacter = + S.getSourceManager().getCharacterData(CC)[0]; + if (FirstContextCharacter == '{') + return false; + } + + return true; +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -7284,7 +8258,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); - } // ... or possibly if we're increasing rank, too else if (TargetBT->getKind() > SourceBT->getKind()) { @@ -7296,22 +8269,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } - // If the target is integral, always warn. + // If the target is integral, always warn. if (TargetBT && TargetBT->isInteger()) { if (S.SourceMgr.isInSystemMacro(CC)) return; - - Expr *InnerE = E->IgnoreParenImpCasts(); - // We also want to warn on, e.g., "int i = -1.234" - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) - if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) - InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); - - if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { - DiagnoseFloatingLiteralImpCast(S, FL, T, CC); - } else { - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer); - } + + DiagnoseFloatingImpCast(S, E, T, CC); } // Detect the case where a call result is converted from floating-point to @@ -7358,7 +8321,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. llvm::APSInt Value(32); - if (E->isIntegerConstantExpr(Value, S.Context)) { + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -7383,10 +8346,34 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); } + if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative && + SourceRange.NonNegative && Source->isSignedIntegerType()) { + // Warn when doing a signed to signed conversion, warn if the positive + // source value is exactly the width of the target type, which will + // cause a negative value to be stored. + + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects) && + !S.SourceMgr.isInSystemMacro(CC)) { + if (isSameWidthConstantConversion(S, E, T, CC)) { + std::string PrettySourceValue = Value.toString(10); + std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); + + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + return; + } + } + + // Fall through for non-constants to give a sign conversion warning. + } + if ((TargetRange.NonNegative && !SourceRange.NonNegative) || (!TargetRange.NonNegative && SourceRange.NonNegative && SourceRange.Width == TargetRange.Width)) { - if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -7429,8 +8416,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } - - return; } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, @@ -7446,7 +8431,6 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T, AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) return CheckImplicitConversion(S, E, T, CC, &ICContext); - return; } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, @@ -7479,7 +8463,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. -static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { +void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); @@ -7583,10 +8567,31 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { } // end anonymous namespace +static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, + unsigned Start, unsigned End) { + bool IllegalParams = false; + for (unsigned I = Start; I <= End; ++I) { + QualType Ty = TheCall->getArg(I)->getType(); + // Taking into account implicit conversions, + // allow any integer within 32 bits range + if (!Ty->isIntegerType() || + S.Context.getTypeSizeInChars(Ty).getQuantity() > 4) { + S.Diag(TheCall->getArg(I)->getLocStart(), + diag::err_opencl_enqueue_kernel_invalid_local_size_type); + IllegalParams = true; + } + // Potentially emit standard warnings for implicit conversions if enabled + // using -Wconversion. + CheckImplicitConversion(S, TheCall->getArg(I), S.Context.UnsignedIntTy, + TheCall->getArg(I)->getLocStart()); + } + return IllegalParams; +} + // Helper function for Sema::DiagnoseAlwaysNonNullPointer. // Returns true when emitting a warning about taking the address of a reference. static bool CheckForReference(Sema &SemaRef, const Expr *E, - PartialDiagnostic PD) { + const PartialDiagnostic &PD) { E = E->IgnoreParenImpCasts(); const FunctionDecl *FD = nullptr; @@ -7681,7 +8686,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, } } - auto ComplainAboutNonnullParamOrCall = [&](bool IsParam) { + auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) { + bool IsParam = isa<NonNullAttr>(NonnullAttr); std::string Str; llvm::raw_string_ostream S(Str); E->printPretty(S, nullptr, getPrintingPolicy()); @@ -7689,13 +8695,14 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, : diag::warn_cast_nonnull_to_bool; Diag(E->getExprLoc(), DiagID) << IsParam << S.str() << E->getSourceRange() << Range << IsEqual; + Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam; }; // If we have a CallExpr that is tagged with returns_nonnull, we can complain. if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) { if (auto *Callee = Call->getDirectCallee()) { - if (Callee->hasAttr<ReturnsNonNullAttr>()) { - ComplainAboutNonnullParamOrCall(false); + if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) { + ComplainAboutNonnullParamOrCall(A); return; } } @@ -7717,25 +8724,25 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, if (const auto* PV = dyn_cast<ParmVarDecl>(D)) { if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV)) { - if (PV->hasAttr<NonNullAttr>()) { - ComplainAboutNonnullParamOrCall(true); + if (const Attr *A = PV->getAttr<NonNullAttr>()) { + ComplainAboutNonnullParamOrCall(A); return; } if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { - auto ParamIter = std::find(FD->param_begin(), FD->param_end(), PV); + auto ParamIter = llvm::find(FD->parameters(), PV); assert(ParamIter != FD->param_end()); unsigned ParamNo = std::distance(FD->param_begin(), ParamIter); for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { if (!NonNull->args_size()) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } for (unsigned ArgNo : NonNull->args()) { if (ArgNo == ParamNo) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } } @@ -7817,7 +8824,6 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, << FixItHint::CreateInsertion(getLocForEndOfToken(E->getLocEnd()), "()"); } - /// Diagnoses "dangerous" implicit conversions within the given /// expression (which is a full expression). Implements -Wconversion /// and -Wsign-compare. @@ -7852,12 +8858,20 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow void Sema::CheckForIntOverflow (Expr *E) { - if (isa<BinaryOperator>(E->IgnoreParenCasts())) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); - else if (auto InitList = dyn_cast<InitListExpr>(E)) - for (Expr *E : InitList->inits()) - if (isa<BinaryOperator>(E->IgnoreParenCasts())) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + // Use a work list to deal with nested struct initializers. + SmallVector<Expr *, 2> Exprs(1, E); + + do { + Expr *E = Exprs.pop_back_val(); + + if (isa<BinaryOperator>(E->IgnoreParenCasts())) { + E->IgnoreParenCasts()->EvaluateForOverflow(Context); + continue; + } + + if (auto InitList = dyn_cast<InitListExpr>(E)) + Exprs.append(InitList->inits().begin(), InitList->inits().end()); + } while (!Exprs.empty()); } namespace { @@ -7875,7 +8889,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { struct Value { explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {} unsigned Parent : 31; - bool Merged : 1; + unsigned Merged : 1; }; SmallVector<Value, 8> Values; @@ -7987,12 +9001,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { Self.ModAsSideEffect = &ModAsSideEffect; } ~SequencedSubexpression() { - for (auto MI = ModAsSideEffect.rbegin(), ME = ModAsSideEffect.rend(); - MI != ME; ++MI) { - UsageInfo &U = Self.UsageMap[MI->first]; + for (auto &M : llvm::reverse(ModAsSideEffect)) { + UsageInfo &U = Self.UsageMap[M.first]; auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; - Self.addUsage(U, MI->first, SideEffectUsage.Use, UK_ModAsValue); - SideEffectUsage = MI->second; + Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue); + SideEffectUsage = M.second; } Self.ModAsSideEffect = OldModAsSideEffect; } @@ -8195,6 +9208,7 @@ public: notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue : UK_ModAsSideEffect); } + void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } @@ -8344,7 +9358,7 @@ public: Tree.merge(Elts[I]); } }; -} +} // end anonymous namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector<Expr *, 8> WorkList; @@ -8403,13 +9417,10 @@ static void diagnoseArrayStarInParamType(Sema &S, QualType PType, /// takes care of any checks that cannot be performed on the /// declaration itself, e.g., that the types of each of the function /// parameters are complete. -bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P, - ParmVarDecl *const *PEnd, +bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, bool CheckParameterNames) { bool HasInvalidParm = false; - for (; P != PEnd; ++P) { - ParmVarDecl *Param = *P; - + for (ParmVarDecl *Param : Parameters) { // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. @@ -8517,21 +9528,12 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -static const Type* getElementType(const Expr *BaseExpr) { - const Type* EltType = BaseExpr->getType().getTypePtr(); - if (EltType->isAnyPointerType()) - return EltType->getPointeeType().getTypePtr(); - else if (EltType->isArrayType()) - return EltType->getBaseElementTypeUnsafe(); - return EltType; -} - /// \brief Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are /// commonly used to emulate flexible arrays in C89 code. -static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size, +static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, const NamedDecl *ND) { if (Size != 1 || !ND) return false; @@ -8580,7 +9582,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (IndexExpr->isValueDependent()) return; - const Type *EffectiveType = getElementType(BaseExpr); + const Type *EffectiveType = + BaseExpr->getType()->getPointeeOrArrayElementType(); BaseExpr = BaseExpr->IgnoreParenCasts(); const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); @@ -8604,7 +9607,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (!size.isStrictlyPositive()) return; - const Type* BaseType = getElementType(BaseExpr); + const Type *BaseType = BaseExpr->getType()->getPointeeOrArrayElementType(); if (BaseType != EffectiveType) { // Make sure we're comparing apples to apples when comparing index to size uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); @@ -8754,7 +9757,7 @@ namespace { Range = e->getSourceRange(); } }; -} +} // end anonymous namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. @@ -8900,7 +9903,7 @@ namespace { } } }; -} +} // end anonymous namespace /// Check whether the given argument is a block which captures a /// variable. @@ -9136,7 +10139,6 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { } } } - } /// Check a message send to see if it's likely to cause a retain cycle. @@ -9340,7 +10342,7 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, return true; } -} // Unnamed namespace +} // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, @@ -9436,7 +10438,6 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, /// DiagnoseSelfMove - Emits a warning if a value is moved to itself. void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc) { - if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) return; @@ -9675,7 +10676,7 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { return false; } -} +} // end anonymous namespace //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// @@ -9806,7 +10807,7 @@ bool GetMatchingCType( TypeInfo = I->second; return true; } -} // unnamed namespace +} // end anonymous namespace void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, @@ -9839,7 +10840,7 @@ bool IsSameCharType(QualType T1, QualType T2) { (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); } -} // unnamed namespace +} // end anonymous namespace void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs) { |