aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-08-16 21:17:51 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-08-16 21:17:51 +0000
commite7145dcb9f6563389ebbfa0572ef7589bdd94b1b (patch)
treeb1b30c4998f6e9769784be87d402e4f8db13e34d /contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
parent3ca95b020283db6244cab92ede73c969253b6a31 (diff)
parent7fd6ba58d980ec2bf312a80444948501dd27d020 (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.cpp1891
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) {