diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp | 1327 |
1 files changed, 1024 insertions, 303 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp index f9f82cdeef43..74742023d1b3 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp @@ -191,7 +191,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return false; } -/// Check the number of arguments, and set the result type to +/// Check the number of arguments and set the result type to /// the argument type. static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) @@ -201,6 +201,87 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { return false; } +/// Check that the value argument for __builtin_is_aligned(value, alignment) and +/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer +/// type (but not a function pointer) and that the alignment is a power-of-two. +static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { + if (checkArgCount(S, TheCall, 2)) + return true; + + clang::Expr *Source = TheCall->getArg(0); + bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned; + + auto IsValidIntegerType = [](QualType Ty) { + return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType(); + }; + QualType SrcTy = Source->getType(); + // We should also be able to use it with arrays (but not functions!). + if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) { + SrcTy = S.Context.getDecayedType(SrcTy); + } + if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) || + SrcTy->isFunctionPointerType()) { + // FIXME: this is not quite the right error message since we don't allow + // floating point types, or member pointers. + S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand) + << SrcTy; + return true; + } + + clang::Expr *AlignOp = TheCall->getArg(1); + if (!IsValidIntegerType(AlignOp->getType())) { + S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int) + << AlignOp->getType(); + return true; + } + Expr::EvalResult AlignResult; + unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1; + // We can't check validity of alignment if it is type dependent. + if (!AlignOp->isInstantiationDependent() && + AlignOp->EvaluateAsInt(AlignResult, S.Context, + Expr::SE_AllowSideEffects)) { + llvm::APSInt AlignValue = AlignResult.Val.getInt(); + llvm::APSInt MaxValue( + llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits)); + if (AlignValue < 1) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1; + return true; + } + if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big) + << MaxValue.toString(10); + return true; + } + if (!AlignValue.isPowerOf2()) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two); + return true; + } + if (AlignValue == 1) { + S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless) + << IsBooleanAlignBuiltin; + } + } + + ExprResult SrcArg = S.PerformCopyInitialization( + InitializedEntity::InitializeParameter(S.Context, SrcTy, false), + SourceLocation(), Source); + if (SrcArg.isInvalid()) + return true; + TheCall->setArg(0, SrcArg.get()); + ExprResult AlignArg = + S.PerformCopyInitialization(InitializedEntity::InitializeParameter( + S.Context, AlignOp->getType(), false), + SourceLocation(), AlignOp); + if (AlignArg.isInvalid()) + return true; + TheCall->setArg(1, AlignArg.get()); + // For align_up/align_down, the return type is the same as the (potentially + // decayed) argument type including qualifiers. For is_aligned(), the result + // is always bool. + TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy); + return false; +} + static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 3)) return true; @@ -340,7 +421,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___strncat_chk: case Builtin::BI__builtin___strncpy_chk: case Builtin::BI__builtin___stpncpy_chk: - case Builtin::BI__builtin___memccpy_chk: { + case Builtin::BI__builtin___memccpy_chk: + case Builtin::BI__builtin___mempcpy_chk: { DiagID = diag::warn_builtin_chk_overflow; IsChkVariant = true; SizeIndex = TheCall->getNumArgs() - 2; @@ -379,7 +461,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BImemmove: case Builtin::BI__builtin_memmove: case Builtin::BImemset: - case Builtin::BI__builtin_memset: { + case Builtin::BI__builtin_memset: + case Builtin::BImempcpy: + case Builtin::BI__builtin_mempcpy: { DiagID = diag::warn_fortify_source_overflow; SizeIndex = TheCall->getNumArgs() - 1; ObjectIndex = 0; @@ -484,7 +568,7 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { const BlockPointerType *BPT = cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); ArrayRef<QualType> Params = - BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes(); + BPT->getPointeeType()->castAs<FunctionProtoType>()->getParamTypes(); unsigned ArgCounter = 0; bool IllegalParams = false; // Iterate through the block parameters until either one is found that is not @@ -583,7 +667,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, const BlockPointerType *BPT = cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); unsigned NumBlockParams = - BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams(); + BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams(); unsigned TotalNumArgs = TheCall->getNumArgs(); // For each argument passed to the block, a corresponding uint needs to @@ -629,7 +713,9 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs < 4) { - S.Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args); + S.Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 4 << NumArgs; return true; } @@ -674,7 +760,7 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // we have a block type, check the prototype const BlockPointerType *BPT = cast<BlockPointerType>(Arg3->getType().getCanonicalType()); - if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) { + if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() > 0) { S.Diag(Arg3->getBeginLoc(), diag::err_opencl_enqueue_kernel_blocks_no_args); return true; @@ -1179,6 +1265,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_alloca_with_align: if (SemaBuiltinAllocaWithAlign(TheCall)) return ExprError(); + LLVM_FALLTHROUGH; + case Builtin::BI__builtin_alloca: + Diag(TheCall->getBeginLoc(), diag::warn_alloca) + << TheCall->getDirectCallee(); break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: @@ -1348,6 +1438,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinAddressof(*this, TheCall)) return ExprError(); break; + case Builtin::BI__builtin_is_aligned: + case Builtin::BI__builtin_align_up: + case Builtin::BI__builtin_align_down: + if (SemaBuiltinAlignment(*this, TheCall, BuiltinID)) + return ExprError(); + break; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: @@ -1530,10 +1626,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::hexagon: if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); @@ -1674,6 +1776,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || + Arch == llvm::Triple::aarch64_32 || Arch == llvm::Triple::aarch64_be; bool IsInt64Long = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong; @@ -1706,6 +1809,14 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; + #include "clang/Basic/arm_mve_builtin_sema.inc" + } +} + bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || @@ -1846,6 +1957,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; + if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) + return true; // For intrinsics which take an immediate value as part of the instruction, // range check them here. @@ -1928,11 +2041,46 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, case AArch64::BI__builtin_arm_dmb: case AArch64::BI__builtin_arm_dsb: case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; + case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + if (checkArgCount(*this, TheCall, 2)) + return true; + + // The first argument needs to be a record field access. + // If it is an array element access, we delay decision + // to BPF backend to check whether the access is a + // field access or not. + Expr *Arg = TheCall->getArg(0); + if (Arg->getType()->getAsPlaceholderType() || + (Arg->IgnoreParens()->getObjectKind() != OK_BitField && + !dyn_cast<MemberExpr>(Arg->IgnoreParens()) && + !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens()))) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field) + << 1 << Arg->getSourceRange(); + return true; + } + + // The second argument needs to be a constant int + llvm::APSInt Value; + if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + + TheCall->setType(Context.UnsignedIntTy); + return false; +} + bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { struct BuiltinAndString { unsigned BuiltinID; @@ -2993,8 +3141,37 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CheckHexagonBuiltinArgument(BuiltinID, TheCall); } +bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + return CheckMipsBuiltinCpu(BuiltinID, TheCall) || + CheckMipsBuiltinArgument(BuiltinID, TheCall); +} + +bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { + const TargetInfo &TI = Context.getTargetInfo(); + + if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_lwx) { + if (!TI.hasFeature("dsp")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp); + } + + if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) { + if (!TI.hasFeature("dspr2")) + return Diag(TheCall->getBeginLoc(), + diag::err_mips_builtin_requires_dspr2); + } + + if (Mips::BI__builtin_msa_add_a_b <= BuiltinID && + BuiltinID <= Mips::BI__builtin_msa_xori_b) { + if (!TI.hasFeature("msa")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa); + } + + return false; +} -// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the +// CheckMipsBuiltinArgument - Checks the constant value passed to the // intrinsic is correct. The switch statement is ordered by DSP, MSA. The // ordering for DSP is unspecified. MSA is ordered by the data format used // by the underlying instruction i.e., df/m, df/n and then by size. @@ -3003,7 +3180,7 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, // definitions from include/clang/Basic/BuiltinsMips.def. // FIXME: GCC is strict on signedness for some of these intrinsics, we should // be too. -bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0, m = 0; switch (BuiltinID) { default: return false; @@ -3213,6 +3390,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_altivec_crypto_vshasigmad: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + case PPC::BI__builtin_altivec_dss: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break; case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break; @@ -3222,6 +3401,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_altivec_dst: + case PPC::BI__builtin_altivec_dstt: + case PPC::BI__builtin_altivec_dstst: + case PPC::BI__builtin_altivec_dststt: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: return SemaBuiltinVSX(TheCall); @@ -3532,9 +3716,11 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit // is set. If the intrinsic has rounding control(bits 1:0), make sure its only - // combined with ROUND_NO_EXC. + // combined with ROUND_NO_EXC. If the intrinsic does not have rounding + // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together. if (Result == 4/*ROUND_CUR_DIRECTION*/ || Result == 8/*ROUND_NO_EXC*/ || + (!HasRC && Result == 12/*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) || (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) return false; @@ -4449,7 +4635,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; + return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()}, + DRE->getSourceRange(), TheCall->getRParenLoc(), Args, + Op); +} +ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op, + AtomicArgumentOrder ArgOrder) { // All the non-OpenCL operations take one of the following forms. // The OpenCL operations take the __c11 forms with one extra argument for // synchronization scope. @@ -4496,20 +4691,19 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm, "need to update code for modified forms"); static_assert(AtomicExpr::AO__c11_atomic_init == 0 && - AtomicExpr::AO__c11_atomic_fetch_xor + 1 == + AtomicExpr::AO__c11_atomic_fetch_min + 1 == AtomicExpr::AO__atomic_load, "need to update code for modified C11 atomics"); bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init && Op <= AtomicExpr::AO__opencl_atomic_fetch_max; bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init && - Op <= AtomicExpr::AO__c11_atomic_fetch_xor) || + Op <= AtomicExpr::AO__c11_atomic_fetch_min) || IsOpenCL; bool IsN = Op == AtomicExpr::AO__atomic_load_n || Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; - bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -4538,8 +4732,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_sub: - case AtomicExpr::AO__opencl_atomic_fetch_min: - case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: @@ -4560,12 +4752,14 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: - Form = Arithmetic; - break; - + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: + case AtomicExpr::AO__atomic_min_fetch: + case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_max: - IsMinMax = true; Form = Arithmetic; break; @@ -4596,21 +4790,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) ++AdjustedNumArgs; // Check we have the right number of arguments. - if (TheCall->getNumArgs() < AdjustedNumArgs) { - Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + if (Args.size() < AdjustedNumArgs) { + Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args) + << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) + << ExprRange; return ExprError(); - } else if (TheCall->getNumArgs() > AdjustedNumArgs) { - Diag(TheCall->getArg(AdjustedNumArgs)->getBeginLoc(), + } else if (Args.size() > AdjustedNumArgs) { + Diag(Args[AdjustedNumArgs]->getBeginLoc(), diag::err_typecheck_call_too_many_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) + << ExprRange; return ExprError(); } // Inspect the first argument of the atomic operation. - Expr *Ptr = TheCall->getArg(0); + Expr *Ptr = Args[0]; ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); if (ConvertedPtr.isInvalid()) return ExprError(); @@ -4618,7 +4812,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); if (!pointerType) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4628,21 +4822,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, QualType ValType = AtomTy; // 'C' if (IsC11) { if (!AtomTy->isAtomicType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) || AtomTy.getAddressSpace() == LangAS::opencl_constant) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic) << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - ValType = AtomTy->getAs<AtomicType>()->getValueType(); + ValType = AtomTy->castAs<AtomicType>()->getValueType(); } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4653,20 +4847,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // gcc does not enforce these rules for GNU atomics, but we do so for sanity. if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (IsMinMax) { - const BuiltinType *BT = ValType->getAs<BuiltinType>(); - if (!BT || (BT->getKind() != BuiltinType::Int && - BT->getKind() != BuiltinType::UInt)) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_int32_or_ptr); - return ExprError(); - } - } - if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_bitwise_needs_atomic_int) + if (!IsAddSub && !ValType->isIntegerType()) { + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4678,7 +4864,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) { // For __atomic_*_n operations, the value type must be a scalar integral or // pointer type which is 1, 2, 4, 8 or 16 bytes in length. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4687,7 +4873,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, !AtomTy->isScalarType()) { // For GNU atomics, require a trivially-copyable type. This is not part of // the GNU atomics specification, but we enforce it for sanity. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_trivial_copy) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4703,7 +4889,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case Qualifiers::OCL_Autoreleasing: // FIXME: Can this happen? By this point, ValType should be known // to be trivially copyable. - Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) + Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership) << ValType << Ptr->getSourceRange(); return ExprError(); } @@ -4730,19 +4916,56 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, IsPassedByAddress = true; } + SmallVector<Expr *, 5> APIOrderedArgs; + if (ArgOrder == Sema::AtomicArgumentOrder::AST) { + APIOrderedArgs.push_back(Args[0]); + switch (Form) { + case Init: + case Load: + APIOrderedArgs.push_back(Args[1]); // Val1/Order + break; + case LoadCopy: + case Copy: + case Arithmetic: + case Xchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case GNUXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[3]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case C11CmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + case GNUCmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[5]); // Weak + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + } + } else + APIOrderedArgs.append(Args.begin(), Args.end()); + // The first argument's non-CV pointer type is used to deduce the type of // subsequent arguments, except for: // - weak flag (always converted to bool) // - memory order (always converted to int) // - scope (always converted to int) - for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { + for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { case 0: // The first argument is always a pointer. It has a fixed type. // It is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); // Nothing else to do: we already know all we want about this pointer. continue; case 1: @@ -4754,16 +4977,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; else if (Form == Copy || Form == Xchg) { - if (IsPassedByAddress) + if (IsPassedByAddress) { // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], + ExprRange.getBegin()); + } Ty = ByValType; } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { - Expr *ValArg = TheCall->getArg(i); + Expr *ValArg = APIOrderedArgs[i]; // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, ValArg, DRE->getBeginLoc()); + CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = @@ -4778,7 +5003,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The third argument to compare_exchange / GNU exchange is the desired // value, either by-value (for the C11 and *_n variant) or as a pointer. if (IsPassedByAddress) - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); Ty = ByValType; break; case 3: @@ -4793,11 +5018,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Ty, false); - ExprResult Arg = TheCall->getArg(i); + ExprResult Arg = APIOrderedArgs[i]; Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; - TheCall->setArg(i, Arg.get()); + APIOrderedArgs[i] = Arg.get(); } // Permute the arguments into a 'consistent' order. @@ -4806,36 +5031,36 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, switch (Form) { case Init: // Note, AtomicExpr::getVal1() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case Load: - SubExprs.push_back(TheCall->getArg(1)); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Order break; case LoadCopy: case Copy: case Arithmetic: case Xchg: - SubExprs.push_back(TheCall->getArg(2)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case GNUXchg: // Note, AtomicExpr::getVal2() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case C11CmpXchg: - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(4)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[4]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case GNUCmpXchg: - SubExprs.push_back(TheCall->getArg(4)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(5)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 - SubExprs.push_back(TheCall->getArg(3)); // Weak + SubExprs.push_back(APIOrderedArgs[4]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[5]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Weak break; } @@ -4849,7 +5074,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { - auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1); + auto *Scope = Args[Args.size() - 1]; llvm::APSInt Result(32); if (Scope->isIntegerConstantExpr(Result, Context) && !ScopeModel->isValid(Result.getZExtValue())) { @@ -4859,9 +5084,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, SubExprs.push_back(Scope); } - AtomicExpr *AE = - new (Context) AtomicExpr(TheCall->getCallee()->getBeginLoc(), SubExprs, - ResultType, Op, TheCall->getRParenLoc()); + AtomicExpr *AE = new (Context) + AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc); if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || @@ -5404,13 +5628,14 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); bool IsX64 = TT.getArch() == llvm::Triple::x86_64; - bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64; + bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 || + TT.getArch() == llvm::Triple::aarch64_32); bool IsWindows = TT.isOSWindows(); bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; if (IsX64 || IsAArch64) { CallingConv CC = CC_C; if (const FunctionDecl *FD = S.getCurFunctionDecl()) - CC = FD->getType()->getAs<FunctionType>()->getCallConv(); + CC = FD->getType()->castAs<FunctionType>()->getCallConv(); if (IsMSVAStart) { // Don't allow this in System V ABI functions. if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64)) @@ -5540,7 +5765,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; if (!Type->isEnumeralType()) return true; - const EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); + const EnumDecl *ED = Type->castAs<EnumType>()->getDecl(); return !(ED && Context.typesAreCompatible(ED->getPromotionType(), Type)); }()) { @@ -5621,7 +5846,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { // Do standard promotions between the two arguments, returning their common // type. - QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + QualType Res = UsualArithmeticConversions( + OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison); if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) return true; @@ -5661,36 +5887,41 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { << SourceRange(TheCall->getArg(NumArgs)->getBeginLoc(), (*(TheCall->arg_end() - 1))->getEndLoc()); + // __builtin_fpclassify is the only case where NumArgs != 1, so we can count + // on all preceding parameters just being int. Try all of those. + for (unsigned i = 0; i < NumArgs - 1; ++i) { + Expr *Arg = TheCall->getArg(i); + + if (Arg->isTypeDependent()) + return false; + + ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, AA_Passing); + + if (Res.isInvalid()) + return true; + TheCall->setArg(i, Res.get()); + } + Expr *OrigArg = TheCall->getArg(NumArgs-1); if (OrigArg->isTypeDependent()) return false; + // Usual Unary Conversions will convert half to float, which we want for + // machines that use fp16 conversion intrinsics. Else, we wnat to leave the + // type how it is, but do normal L->Rvalue conversions. + if (Context.getTargetInfo().useFP16ConversionIntrinsics()) + OrigArg = UsualUnaryConversions(OrigArg).get(); + else + OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get(); + TheCall->setArg(NumArgs - 1, OrigArg); + // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) return Diag(OrigArg->getBeginLoc(), diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> float, double, or - // long double, remove it. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { - // Only remove standard FloatCasts, leaving other casts inplace - if (Cast->getCastKind() == CK_FloatingCast) { - Expr *CastArg = Cast->getSubExpr(); - if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert( - (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && - "promotion from float to either float, double, or long double is " - "the only expected cast here"); - Cast->setSubExpr(nullptr); - TheCall->setArg(NumArgs-1, CastArg); - } - } - } - return false; } @@ -5780,7 +6011,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); - numElements = LHSType->getAs<VectorType>()->getNumElements(); + numElements = LHSType->castAs<VectorType>()->getNumElements(); unsigned numResElements = TheCall->getNumArgs() - 2; // Check to see if we have a call with 2 vector arguments, the unary shuffle @@ -5788,7 +6019,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // same number of elts as lhs. if (TheCall->getNumArgs() == 2) { if (!RHSType->hasIntegerRepresentation() || - RHSType->getAs<VectorType>()->getNumElements() != numElements) + RHSType->castAs<VectorType>()->getNumElements() != numElements) return ExprError(Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() @@ -5801,7 +6032,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); } else if (numElements != numResElements) { - QualType eltType = LHSType->getAs<VectorType>()->getElementType(); + QualType eltType = LHSType->castAs<VectorType>()->getElementType(); resType = Context.getVectorType(eltType, numResElements, VectorType::GenericVector); } @@ -5858,8 +6089,8 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, diag::err_convertvector_non_vector_type)); if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { - unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements(); - unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements(); + unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements(); + unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements(); if (SrcElts != DstElts) return ExprError(Diag(BuiltinLoc, diag::err_convertvector_incompatible_vector) @@ -5961,6 +6192,12 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { if (!Result.isPowerOf2()) return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) << Arg->getSourceRange(); + + // Alignment calculations can wrap around if it's greater than 2**29. + unsigned MaximumAlignment = 536870912; + if (Result > MaximumAlignment) + Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great) + << Arg->getSourceRange() << MaximumAlignment; } if (NumArgs > 2) { @@ -6127,6 +6364,101 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a +/// constant expression representing a power of 2. +bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if + // and only if x is a power of 2. + if (Result.isStrictlyPositive() && (Result & (Result - 1)) == 0) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2) + << Arg->getSourceRange(); +} + +static bool IsShiftedByte(llvm::APSInt Value) { + if (Value.isNegative()) + return false; + + // Check if it's a shifted byte, by shifting it down + while (true) { + // If the value fits in the bottom byte, the check passes. + if (Value < 0x100) + return true; + + // Otherwise, if the value has _any_ bits in the bottom byte, the check + // fails. + if ((Value & 0xFF) != 0) + return false; + + // If the bottom 8 bits are all 0, but something above that is nonzero, + // then shifting the value right by 8 bits won't affect whether it's a + // shifted byte or not. So do that, and go round again. + Value >>= 8; + } +} + +/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is +/// a constant expression representing an arbitrary byte value shifted left by +/// a multiple of 8 bits. +bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + if (IsShiftedByte(Result)) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte) + << Arg->getSourceRange(); +} + +/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of +/// TheCall is a constant expression representing either a shifted byte value, +/// or a value of the form 0x??FF (i.e. a member of the arithmetic progression +/// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some +/// Arm MVE intrinsics. +bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, + int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Check to see if it's in either of the required forms. + if (IsShiftedByte(Result) || + (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF)) + return false; + + return Diag(TheCall->getBeginLoc(), + diag::err_argument_not_shifted_byte_or_xxff) + << Arg->getSourceRange(); +} + /// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == AArch64::BI__builtin_arm_irg) { @@ -6570,7 +6902,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg); + UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a @@ -6583,7 +6916,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, - llvm::APSInt Offset) { + llvm::APSInt Offset, + bool IgnoreStringsWithoutSpecifiers = false) { if (S.isConstantEvaluated()) return SLCT_NotALiteral; tryAgain: @@ -6634,17 +6968,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); + CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); if (Left == SLCT_NotALiteral || !CheckRight) { return Left; } } - StringLiteralCheckType Right = - checkFormatStringExpr(S, C->getFalseExpr(), Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg, Offset); + StringLiteralCheckType Right = checkFormatStringExpr( + S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, + Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); return (CheckLeft && Left < Right) ? Left : Right; } @@ -6748,7 +7082,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); StringLiteralCheckType Result = checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); if (IsFirst) { CommonResult = Result; IsFirst = false; @@ -6766,7 +7101,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg, Offset); + UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); } } } @@ -6775,12 +7111,28 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, } case Stmt::ObjCMessageExprClass: { const auto *ME = cast<ObjCMessageExpr>(E); - if (const auto *ND = ME->getMethodDecl()) { - if (const auto *FA = ND->getAttr<FormatArgAttr>()) { + if (const auto *MD = ME->getMethodDecl()) { + if (const auto *FA = MD->getAttr<FormatArgAttr>()) { + // As a special case heuristic, if we're using the method -[NSBundle + // localizedStringForKey:value:table:], ignore any key strings that lack + // format specifiers. The idea is that if the key doesn't have any + // format specifiers then its probably just a key to map to the + // localized strings. If it does have format specifiers though, then its + // likely that the text of the key is the format string in the + // programmer's language, and should be checked. + const ObjCInterfaceDecl *IFace; + if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) && + IFace->getIdentifier()->isStr("NSBundle") && + MD->getSelector().isKeywordSelector( + {"localizedStringForKey", "value", "table"})) { + IgnoreStringsWithoutSpecifiers = true; + } + const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); } } @@ -6804,7 +7156,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx, firstDataArg, Type, InFunctionCall, CallType, - CheckedVarArgs, UncoveredArg); + CheckedVarArgs, UncoveredArg, + IgnoreStringsWithoutSpecifiers); return SLCT_CheckedLiteral; } @@ -8072,9 +8425,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - const analyze_printf::ArgType::MatchKind Match = - AT.matchesType(S.Context, ExprTy); - bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; + // Diagnose attempts to print a boolean value as a character. Unlike other + // -Wformat diagnostics, this is fine from a type perspective, but it still + // doesn't make sense. + if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg && + E->isKnownToHaveBooleanValue()) { + const CharSourceRange &CSR = + getSpecifierRange(StartSpecifier, SpecifierLen); + SmallString<4> FSString; + llvm::raw_svector_ostream os(FSString); + FS.toString(os); + EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character) + << FSString, + E->getExprLoc(), false, CSR); + return true; + } + + analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); if (Match == analyze_printf::ArgType::Match) return true; @@ -8093,9 +8460,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // function. if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { - // All further checking is done on the subexpression. - if (AT.matchesType(S.Context, ExprTy)) + // All further checking is done on the subexpression + const analyze_printf::ArgType::MatchKind ImplicitMatch = + AT.matchesType(S.Context, ExprTy); + if (ImplicitMatch == analyze_printf::ArgType::Match) return true; + if (ImplicitMatch == ArgType::NoMatchPedantic || + ImplicitMatch == ArgType::NoMatchTypeConfusion) + Match = ImplicitMatch; } } } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) { @@ -8157,7 +8529,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && (AT.isSizeT() || AT.isPtrdiffT()) && AT.matchesType(S.Context, CastTy)) - Pedantic = true; + Match = ArgType::NoMatchPedantic; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } @@ -8177,10 +8549,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { - unsigned Diag = - Pedantic - ? diag::warn_format_conversion_argument_type_mismatch_pedantic - : diag::warn_format_conversion_argument_type_mismatch; + unsigned Diag; + switch (Match) { + case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::NoMatchPedantic: + Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + break; + case ArgType::NoMatchTypeConfusion: + Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; + break; + case ArgType::NoMatch: + Diag = diag::warn_format_conversion_argument_type_mismatch; + break; + } + // In this case, the specifier is wrong and should be changed to match // the argument. EmitFormatDiagnostic(S.PDiag(Diag) @@ -8236,7 +8618,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; - unsigned Diag = Pedantic + unsigned Diag = Match == ArgType::NoMatchPedantic ? diag::warn_format_argument_needs_cast_pedantic : diag::warn_format_argument_needs_cast; EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum @@ -8263,10 +8645,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { - unsigned Diag = - Pedantic - ? diag::warn_format_conversion_argument_type_mismatch_pedantic - : diag::warn_format_conversion_argument_type_mismatch; + unsigned Diag; + switch (Match) { + case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::NoMatchPedantic: + Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + break; + case ArgType::NoMatchTypeConfusion: + Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; + break; + case ArgType::NoMatch: + Diag = diag::warn_format_conversion_argument_type_mismatch; + break; + } EmitFormatDiagnostic( S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy @@ -8495,7 +8886,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg) { + UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( @@ -8516,6 +8908,11 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); const unsigned numDataArgs = Args.size() - firstDataArg; + if (IgnoreStringsWithoutSpecifiers && + !analyze_format_string::parseFormatStringHasFormattingSpecifiers( + Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) + return; + // Emit a warning if the string literal is truncated and does not contain an // embedded null character. if (TypeSize <= StrRef.size() && @@ -8989,7 +9386,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call, auto IsLiteralZeroArg = [](const Expr* E) -> bool { const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); if (!MTE) return false; - const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr()); + const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr()); if (!Num) return false; if (Num->getValue() != 0) return false; return true; @@ -10195,7 +10592,8 @@ static bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC, + bool IsListInit = false); static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. @@ -10627,7 +11025,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, return false; if (BitfieldType->isEnumeralType()) { - EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl(); + EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()->getDecl(); // If the underlying enum type was not explicitly specified as an unsigned // type and the enum contain only positive values, MSVC++ will cause an // inconsistency by storing this as a signed type. @@ -10792,6 +11190,26 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +static bool isObjCSignedCharBool(Sema &S, QualType Ty) { + return Ty->isSpecificBuiltinType(BuiltinType::SChar) && + S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty); +} + +static void adornObjCBoolConversionDiagWithTernaryFixit( + Sema &S, Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) { + Expr *Ignored = SourceExpr->IgnoreImplicit(); + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ignored)) + Ignored = OVE->getSourceExpr(); + bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) || + isa<BinaryOperator>(Ignored) || + isa<CXXOperatorCallExpr>(Ignored); + SourceLocation EndLoc = S.getLocForEndOfToken(SourceExpr->getEndLoc()); + if (NeedsParens) + Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); +} + /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext) { @@ -10811,6 +11229,13 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, bool IsConstant = E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); if (!IsConstant) { + if (isObjCSignedCharBool(S, T)) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool) + << E->getType()); + } + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } @@ -10822,6 +11247,23 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, llvm::APFloat::opStatus Result = Value.convertToInteger( IntegerValue, llvm::APFloat::rmTowardZero, &isExact); + // 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 + // truncate a digit by accident in edge cases). Ideally, APFloat::toString + // would automatically print the shortest representation, but it's a bit + // tricky to implement. + SmallString<16> PrettySourceValue; + unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); + precision = (precision * 59 + 195) / 196; + Value.toString(PrettySourceValue, precision); + + if (isObjCSignedCharBool(S, T) && IntegerValue != 0 && IntegerValue != 1) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool) + << PrettySourceValue); + } + if (Result == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, @@ -10865,16 +11307,6 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, 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 - // truncate a digit by accident in edge cases). Ideally, APFloat::toString - // would automatically print the shortest representation, but it's a bit - // tricky to implement. - SmallString<16> PrettySourceValue; - unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); - precision = (precision * 59 + 195) / 196; - Value.toString(PrettySourceValue, precision); - SmallString<16> PrettyTargetValue; if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; @@ -11151,14 +11583,59 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, return true; } -static bool isObjCSignedCharBool(Sema &S, QualType Ty) { - return Ty->isSpecificBuiltinType(BuiltinType::SChar) && - S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty); +static const IntegerLiteral *getIntegerLiteral(Expr *E) { + const auto *IL = dyn_cast<IntegerLiteral>(E); + if (!IL) { + if (auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Minus) + return dyn_cast<IntegerLiteral>(UO->getSubExpr()); + } + } + + return IL; } -static void -CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, - bool *ICContext = nullptr) { +static void DiagnoseIntInBoolContext(Sema &S, Expr *E) { + E = E->IgnoreParenImpCasts(); + SourceLocation ExprLoc = E->getExprLoc(); + + if (const auto *BO = dyn_cast<BinaryOperator>(E)) { + BinaryOperator::Opcode Opc = BO->getOpcode(); + Expr::EvalResult Result; + // Do not diagnose unsigned shifts. + if (Opc == BO_Shl) { + const auto *LHS = getIntegerLiteral(BO->getLHS()); + const auto *RHS = getIntegerLiteral(BO->getRHS()); + if (LHS && LHS->getValue() == 0) + S.Diag(ExprLoc, diag::warn_left_shift_always) << 0; + else if (!E->isValueDependent() && LHS && RHS && + RHS->getValue().isNonNegative() && + E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) + S.Diag(ExprLoc, diag::warn_left_shift_always) + << (Result.Val.getInt() != 0); + else if (E->getType()->isSignedIntegerType()) + S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E; + } + } + + if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { + const auto *LHS = getIntegerLiteral(CO->getTrueExpr()); + const auto *RHS = getIntegerLiteral(CO->getFalseExpr()); + if (!LHS || !RHS) + return; + if ((LHS->getValue() == 0 || LHS->getValue() == 1) && + (RHS->getValue() == 0 || RHS->getValue() == 1)) + // Do not diagnose common idioms. + return; + if (LHS->getValue() != 0 && RHS->getValue() != 0) + S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true); + } +} + +static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC, + bool *ICContext = nullptr, + bool IsListInit = false) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -11205,19 +11682,13 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) { Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.getASTContext(), - Expr::SE_AllowSideEffects) && - Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { - auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool) - << Result.Val.getInt().toString(10); - Expr *Ignored = E->IgnoreImplicit(); - bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) || - isa<BinaryOperator>(Ignored) || - isa<CXXOperatorCallExpr>(Ignored); - SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc()); - if (NeedsParens) - Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); + Expr::SE_AllowSideEffects)) { + if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { + adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CC, diag::warn_impcast_constant_value_to_objc_bool) + << Result.Val.getInt().toString(10)); + } return; } } @@ -11400,10 +11871,61 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, } } + // If we are casting an integer type to a floating point type without + // initialization-list syntax, we might lose accuracy if the floating + // point type has a narrower significand than the integer type. + if (SourceBT && TargetBT && SourceBT->isIntegerType() && + TargetBT->isFloatingType() && !IsListInit) { + // Determine the number of precision bits in the source integer type. + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); + unsigned int SourcePrecision = SourceRange.Width; + + // Determine the number of precision bits in the + // target floating point type. + unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + + if (SourcePrecision > 0 && TargetPrecision > 0 && + SourcePrecision > TargetPrecision) { + + llvm::APSInt SourceInt; + if (E->isIntegerConstantExpr(SourceInt, S.Context)) { + // If the source integer is a constant, convert it to the target + // floating point type. Issue a warning if the value changes + // during the whole conversion. + llvm::APFloat TargetFloatValue( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + llvm::APFloat::opStatus ConversionStatus = + TargetFloatValue.convertFromAPInt( + SourceInt, SourceBT->isSignedInteger(), + llvm::APFloat::rmNearestTiesToEven); + + if (ConversionStatus != llvm::APFloat::opOK) { + std::string PrettySourceValue = SourceInt.toString(10); + SmallString<32> PrettyTargetValue; + TargetFloatValue.toString(PrettyTargetValue, TargetPrecision); + + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_float_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + } + } else { + // Otherwise, the implicit conversion may lose precision. + DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_integer_float_precision); + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); + if (Target->isBooleanType()) + DiagnoseIntInBoolContext(S, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -11412,6 +11934,14 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; + if (isObjCSignedCharBool(S, T) && !Source->isCharType() && + !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) + << E->getType()); + } + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); @@ -11557,6 +12087,9 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); + if (T->isBooleanType()) + DiagnoseIntInBoolContext(S, E); + // If -Wconversion would have warned about either of the candidates // for a signedness conversion to the context type... if (!Suspicious) return; @@ -11590,14 +12123,27 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. -static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, - SourceLocation CC) { +static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, + bool IsListInit/*= false*/) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); + // Propagate whether we are in a C++ list initialization expression. + // If so, we do not issue warnings for implicit int-float conversion + // precision loss, because C++11 narrowing already handles it. + IsListInit = + IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus); + if (E->isTypeDependent() || E->isValueDependent()) return; + if (const auto *UO = dyn_cast<UnaryOperator>(E)) + if (UO->getOpcode() == UO_Not && + UO->getSubExpr()->isKnownToHaveBooleanValue()) + S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool) + << OrigE->getSourceRange() << T->isBooleanType() + << FixItHint::CreateReplacement(UO->getBeginLoc(), "!"); + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -11614,7 +12160,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. if (E->getType() != T) - CheckImplicitConversion(S, E, T, CC); + CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit); // Now continue drilling into this expression. @@ -11624,7 +12170,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // FIXME: Use a more uniform representation for this. for (auto *SE : POE->semantics()) if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE)) - AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); + AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit); } // Skip past explicit casts. @@ -11632,7 +12178,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, E = CE->getSubExpr()->IgnoreParenImpCasts(); if (!CE->getType()->isVoidType() && E->getType()->isAtomicType()) S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); - return AnalyzeImplicitConversions(S, E, CC); + return AnalyzeImplicitConversions(S, E, CC, IsListInit); } if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { @@ -11671,7 +12217,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // Ignore checking string literals that are in logical and operators. // This is a common pattern for asserts. continue; - AnalyzeImplicitConversions(S, ChildExpr, CC); + AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit); } if (BO && BO->isLogicalOp()) { @@ -12010,8 +12556,8 @@ namespace { /// Visitor for expressions which looks for unsequenced operations on the /// same object. -class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { - using Base = EvaluatedExprVisitor<SequenceChecker>; +class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { + using Base = ConstEvaluatedExprVisitor<SequenceChecker>; /// A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we @@ -12081,7 +12627,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; /// An object for which we can track unsequenced uses. - using Object = NamedDecl *; + using Object = const NamedDecl *; /// Different flavors of object usage which we track. We only track the /// least-sequenced usage of each kind. @@ -12100,17 +12646,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { UK_Count = UK_ModAsSideEffect + 1 }; + /// Bundle together a sequencing region and the expression corresponding + /// to a specific usage. One Usage is stored for each usage kind in UsageInfo. struct Usage { - Expr *Use; + const Expr *UsageExpr; SequenceTree::Seq Seq; - Usage() : Use(nullptr), Seq() {} + Usage() : UsageExpr(nullptr), Seq() {} }; struct UsageInfo { Usage Uses[UK_Count]; - /// Have we issued a diagnostic for this variable already? + /// Have we issued a diagnostic for this object already? bool Diagnosed; UsageInfo() : Uses(), Diagnosed(false) {} @@ -12134,7 +12682,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// Expressions to check later. We defer checking these to reduce /// stack usage. - SmallVectorImpl<Expr *> &WorkList; + SmallVectorImpl<const Expr *> &WorkList; /// RAII object wrapping the visitation of a sequenced subexpression of an /// expression. At the end of this process, the side-effects of the evaluation @@ -12148,10 +12696,13 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } ~SequencedSubexpression() { - for (auto &M : llvm::reverse(ModAsSideEffect)) { - UsageInfo &U = Self.UsageMap[M.first]; - auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; - Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue); + for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) { + // Add a new usage with usage kind UK_ModAsValue, and then restore + // the previous usage with UK_ModAsSideEffect (thus clearing it if + // the previous one was empty). + UsageInfo &UI = Self.UsageMap[M.first]; + auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect]; + Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue); SideEffectUsage = M.second; } Self.ModAsSideEffect = OldModAsSideEffect; @@ -12195,49 +12746,60 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// Find the object which is produced by the specified expression, /// if any. - Object getObject(Expr *E, bool Mod) const { + Object getObject(const Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec)) return getObject(UO->getSubExpr(), Mod); - } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { if (BO->getOpcode() == BO_Comma) return getObject(BO->getRHS(), Mod); if (Mod && BO->isAssignmentOp()) return getObject(BO->getLHS(), Mod); - } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { // FIXME: Check for more interesting cases, like "x.n = ++x.n". if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts())) return ME->getMemberDecl(); - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) // FIXME: If this is a reference, map through to its value. return DRE->getDecl(); return nullptr; } - /// Note that an object was modified or used by an expression. - void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { + /// Note that an object \p O was modified or used by an expression + /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for + /// the object \p O as obtained via the \p UsageMap. + void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) { + // Get the old usage for the given object and usage kind. Usage &U = UI.Uses[UK]; - if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { + if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) { + // If we have a modification as side effect and are in a sequenced + // subexpression, save the old Usage so that we can restore it later + // in SequencedSubexpression::~SequencedSubexpression. if (UK == UK_ModAsSideEffect && ModAsSideEffect) ModAsSideEffect->push_back(std::make_pair(O, U)); - U.Use = Ref; + // Then record the new usage with the current sequencing region. + U.UsageExpr = UsageExpr; U.Seq = Region; } } - /// Check whether a modification or use conflicts with a prior usage. - void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, - bool IsModMod) { + /// Check whether a modification or use of an object \p O in an expression + /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is + /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap. + /// \p IsModMod is true when we are checking for a mod-mod unsequenced + /// usage and false we are checking for a mod-use unsequenced usage. + void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, + UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) return; const Usage &U = UI.Uses[OtherKind]; - if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) + if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) return; - Expr *Mod = U.Use; - Expr *ModOrUse = Ref; + const Expr *Mod = U.UsageExpr; + const Expr *ModOrUse = UsageExpr; if (OtherKind == UK_Use) std::swap(Mod, ModOrUse); @@ -12249,47 +12811,79 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { UI.Diagnosed = true; } - void notePreUse(Object O, Expr *Use) { - UsageInfo &U = UsageMap[O]; + // A note on note{Pre, Post}{Use, Mod}: + // + // (It helps to follow the algorithm with an expression such as + // "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced + // operations before C++17 and both are well-defined in C++17). + // + // When visiting a node which uses/modify an object we first call notePreUse + // or notePreMod before visiting its sub-expression(s). At this point the + // children of the current node have not yet been visited and so the eventual + // uses/modifications resulting from the children of the current node have not + // been recorded yet. + // + // We then visit the children of the current node. After that notePostUse or + // notePostMod is called. These will 1) detect an unsequenced modification + // as side effect (as in "k++ + k") and 2) add a new usage with the + // appropriate usage kind. + // + // We also have to be careful that some operation sequences modification as + // side effect as well (for example: || or ,). To account for this we wrap + // the visitation of such a sub-expression (for example: the LHS of || or ,) + // with SequencedSubexpression. SequencedSubexpression is an RAII object + // which record usages which are modifications as side effect, and then + // downgrade them (or more accurately restore the previous usage which was a + // modification as side effect) when exiting the scope of the sequenced + // subexpression. + + void notePreUse(Object O, const Expr *UseExpr) { + UsageInfo &UI = UsageMap[O]; // Uses conflict with other modifications. - checkUsage(O, U, Use, UK_ModAsValue, false); + checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false); } - void notePostUse(Object O, Expr *Use) { - UsageInfo &U = UsageMap[O]; - checkUsage(O, U, Use, UK_ModAsSideEffect, false); - addUsage(U, O, Use, UK_Use); + void notePostUse(Object O, const Expr *UseExpr) { + UsageInfo &UI = UsageMap[O]; + checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, + /*IsModMod=*/false); + addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use); } - void notePreMod(Object O, Expr *Mod) { - UsageInfo &U = UsageMap[O]; + void notePreMod(Object O, const Expr *ModExpr) { + UsageInfo &UI = UsageMap[O]; // Modifications conflict with other modifications and with uses. - checkUsage(O, U, Mod, UK_ModAsValue, true); - checkUsage(O, U, Mod, UK_Use, false); + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true); + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false); } - void notePostMod(Object O, Expr *Use, UsageKind UK) { - UsageInfo &U = UsageMap[O]; - checkUsage(O, U, Use, UK_ModAsSideEffect, true); - addUsage(U, O, Use, UK); + void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) { + UsageInfo &UI = UsageMap[O]; + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, + /*IsModMod=*/true); + addUsage(O, UI, ModExpr, /*UsageKind=*/UK); } public: - SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList) + SequenceChecker(Sema &S, const Expr *E, + SmallVectorImpl<const Expr *> &WorkList) : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) { Visit(E); + // Silence a -Wunused-private-field since WorkList is now unused. + // TODO: Evaluate if it can be used, and if not remove it. + (void)this->WorkList; } - void VisitStmt(Stmt *S) { + void VisitStmt(const Stmt *S) { // Skip all statements which aren't expressions for now. } - void VisitExpr(Expr *E) { + void VisitExpr(const Expr *E) { // By default, just recurse to evaluated subexpressions. Base::VisitStmt(E); } - void VisitCastExpr(CastExpr *E) { + void VisitCastExpr(const CastExpr *E) { Object O = Object(); if (E->getCastKind() == CK_LValueToRValue) O = getObject(E->getSubExpr(), false); @@ -12301,7 +12895,8 @@ public: notePostUse(O, E); } - void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) { + void VisitSequencedExpressions(const Expr *SequencedBefore, + const Expr *SequencedAfter) { SequenceTree::Seq BeforeRegion = Tree.allocate(Region); SequenceTree::Seq AfterRegion = Tree.allocate(Region); SequenceTree::Seq OldRegion = Region; @@ -12321,17 +12916,46 @@ public: Tree.merge(AfterRegion); } - void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { + void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) { // C++17 [expr.sub]p1: // The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The // expression E1 is sequenced before the expression E2. if (SemaRef.getLangOpts().CPlusPlus17) VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS()); - else - Base::VisitStmt(ASE); + else { + Visit(ASE->getLHS()); + Visit(ASE->getRHS()); + } + } + + void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); } + void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); } + void VisitBinPtrMem(const BinaryOperator *BO) { + // C++17 [expr.mptr.oper]p4: + // Abbreviating pm-expression.*cast-expression as E1.*E2, [...] + // the expression E1 is sequenced before the expression E2. + if (SemaRef.getLangOpts().CPlusPlus17) + VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); + else { + Visit(BO->getLHS()); + Visit(BO->getRHS()); + } } - void VisitBinComma(BinaryOperator *BO) { + void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); } + void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); } + void VisitBinShlShr(const BinaryOperator *BO) { + // C++17 [expr.shift]p4: + // The expression E1 is sequenced before the expression E2. + if (SemaRef.getLangOpts().CPlusPlus17) + VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); + else { + Visit(BO->getLHS()); + Visit(BO->getRHS()); + } + } + + void VisitBinComma(const BinaryOperator *BO) { // C++11 [expr.comma]p1: // Every value computation and side effect associated with the left // expression is sequenced before every value computation and side @@ -12339,47 +12963,77 @@ public: VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); } - void VisitBinAssign(BinaryOperator *BO) { - // The modification is sequenced after the value computation of the LHS - // and RHS, so check it before inspecting the operands and update the + void VisitBinAssign(const BinaryOperator *BO) { + SequenceTree::Seq RHSRegion; + SequenceTree::Seq LHSRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + RHSRegion = Tree.allocate(Region); + LHSRegion = Tree.allocate(Region); + } else { + RHSRegion = Region; + LHSRegion = Region; + } + SequenceTree::Seq OldRegion = Region; + + // C++11 [expr.ass]p1: + // [...] the assignment is sequenced after the value computation + // of the right and left operands, [...] + // + // so check it before inspecting the operands and update the // map afterwards. - Object O = getObject(BO->getLHS(), true); - if (!O) - return VisitExpr(BO); + Object O = getObject(BO->getLHS(), /*Mod=*/true); + if (O) + notePreMod(O, BO); + + if (SemaRef.getLangOpts().CPlusPlus17) { + // C++17 [expr.ass]p1: + // [...] The right operand is sequenced before the left operand. [...] + { + SequencedSubexpression SeqBefore(*this); + Region = RHSRegion; + Visit(BO->getRHS()); + } - notePreMod(O, BO); + Region = LHSRegion; + Visit(BO->getLHS()); - // C++11 [expr.ass]p7: - // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated - // only once. - // - // Therefore, for a compound assignment operator, O is considered used - // everywhere except within the evaluation of E1 itself. - if (isa<CompoundAssignOperator>(BO)) - notePreUse(O, BO); + if (O && isa<CompoundAssignOperator>(BO)) + notePostUse(O, BO); - Visit(BO->getLHS()); + } else { + // C++11 does not specify any sequencing between the LHS and RHS. + Region = LHSRegion; + Visit(BO->getLHS()); - if (isa<CompoundAssignOperator>(BO)) - notePostUse(O, BO); + if (O && isa<CompoundAssignOperator>(BO)) + notePostUse(O, BO); - Visit(BO->getRHS()); + Region = RHSRegion; + Visit(BO->getRHS()); + } // C++11 [expr.ass]p1: - // the assignment is sequenced [...] before the value computation of the - // assignment expression. + // the assignment is sequenced [...] before the value computation of the + // assignment expression. // C11 6.5.16/3 has no such rule. - notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue - : UK_ModAsSideEffect); + Region = OldRegion; + if (O) + notePostMod(O, BO, + SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue + : UK_ModAsSideEffect); + if (SemaRef.getLangOpts().CPlusPlus17) { + Tree.merge(RHSRegion); + Tree.merge(LHSRegion); + } } - void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { + void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } - void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } - void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } - void VisitUnaryPreIncDec(UnaryOperator *UO) { + void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } + void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } + void VisitUnaryPreIncDec(const UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); @@ -12388,13 +13042,14 @@ public: Visit(UO->getSubExpr()); // C++11 [expr.pre.incr]p1: // the expression ++x is equivalent to x+=1 - notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue - : UK_ModAsSideEffect); + notePostMod(O, UO, + SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue + : UK_ModAsSideEffect); } - void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } - void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } - void VisitUnaryPostIncDec(UnaryOperator *UO) { + void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } + void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } + void VisitUnaryPostIncDec(const UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); @@ -12404,67 +13059,129 @@ public: notePostMod(O, UO, UK_ModAsSideEffect); } - /// Don't visit the RHS of '&&' or '||' if it might not be evaluated. - void VisitBinLOr(BinaryOperator *BO) { - // The side-effects of the LHS of an '&&' are sequenced before the - // value computation of the RHS, and hence before the value computation - // of the '&&' itself, unless the LHS evaluates to zero. We treat them - // as if they were unconditionally sequenced. + void VisitBinLOr(const BinaryOperator *BO) { + // C++11 [expr.log.or]p2: + // If the second expression is evaluated, every value computation and + // side effect associated with the first expression is sequenced before + // every value computation and side effect associated with the + // second expression. + SequenceTree::Seq LHSRegion = Tree.allocate(Region); + SequenceTree::Seq RHSRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = LHSRegion; Visit(BO->getLHS()); } - bool Result; - if (Eval.evaluate(BO->getLHS(), Result)) { - if (!Result) - Visit(BO->getRHS()); - } else { - // Check for unsequenced operations in the RHS, treating it as an - // entirely separate evaluation. - // - // FIXME: If there are operations in the RHS which are unsequenced - // with respect to operations outside the RHS, and those operations - // are unconditionally evaluated, diagnose them. - WorkList.push_back(BO->getRHS()); + // C++11 [expr.log.or]p1: + // [...] the second operand is not evaluated if the first operand + // evaluates to true. + bool EvalResult = false; + bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); + bool ShouldVisitRHS = !EvalOK || (EvalOK && !EvalResult); + if (ShouldVisitRHS) { + Region = RHSRegion; + Visit(BO->getRHS()); } - } - void VisitBinLAnd(BinaryOperator *BO) { + + Region = OldRegion; + Tree.merge(LHSRegion); + Tree.merge(RHSRegion); + } + + void VisitBinLAnd(const BinaryOperator *BO) { + // C++11 [expr.log.and]p2: + // If the second expression is evaluated, every value computation and + // side effect associated with the first expression is sequenced before + // every value computation and side effect associated with the + // second expression. + SequenceTree::Seq LHSRegion = Tree.allocate(Region); + SequenceTree::Seq RHSRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = LHSRegion; Visit(BO->getLHS()); } - bool Result; - if (Eval.evaluate(BO->getLHS(), Result)) { - if (Result) - Visit(BO->getRHS()); - } else { - WorkList.push_back(BO->getRHS()); + // C++11 [expr.log.and]p1: + // [...] the second operand is not evaluated if the first operand is false. + bool EvalResult = false; + bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); + bool ShouldVisitRHS = !EvalOK || (EvalOK && EvalResult); + if (ShouldVisitRHS) { + Region = RHSRegion; + Visit(BO->getRHS()); } - } - // Only visit the condition, unless we can be sure which subexpression will - // be chosen. - void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) { + Region = OldRegion; + Tree.merge(LHSRegion); + Tree.merge(RHSRegion); + } + + void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) { + // C++11 [expr.cond]p1: + // [...] Every value computation and side effect associated with the first + // expression is sequenced before every value computation and side effect + // associated with the second or third expression. + SequenceTree::Seq ConditionRegion = Tree.allocate(Region); + + // No sequencing is specified between the true and false expression. + // However since exactly one of both is going to be evaluated we can + // consider them to be sequenced. This is needed to avoid warning on + // something like "x ? y+= 1 : y += 2;" in the case where we will visit + // both the true and false expressions because we can't evaluate x. + // This will still allow us to detect an expression like (pre C++17) + // "(x ? y += 1 : y += 2) = y". + // + // We don't wrap the visitation of the true and false expression with + // SequencedSubexpression because we don't want to downgrade modifications + // as side effect in the true and false expressions after the visition + // is done. (for example in the expression "(x ? y++ : y++) + y" we should + // not warn between the two "y++", but we should warn between the "y++" + // and the "y". + SequenceTree::Seq TrueRegion = Tree.allocate(Region); + SequenceTree::Seq FalseRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = ConditionRegion; Visit(CO->getCond()); } - bool Result; - if (Eval.evaluate(CO->getCond(), Result)) - Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr()); - else { - WorkList.push_back(CO->getTrueExpr()); - WorkList.push_back(CO->getFalseExpr()); + // C++11 [expr.cond]p1: + // [...] The first expression is contextually converted to bool (Clause 4). + // It is evaluated and if it is true, the result of the conditional + // expression is the value of the second expression, otherwise that of the + // third expression. Only one of the second and third expressions is + // evaluated. [...] + bool EvalResult = false; + bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult); + bool ShouldVisitTrueExpr = !EvalOK || (EvalOK && EvalResult); + bool ShouldVisitFalseExpr = !EvalOK || (EvalOK && !EvalResult); + if (ShouldVisitTrueExpr) { + Region = TrueRegion; + Visit(CO->getTrueExpr()); + } + if (ShouldVisitFalseExpr) { + Region = FalseRegion; + Visit(CO->getFalseExpr()); } + + Region = OldRegion; + Tree.merge(ConditionRegion); + Tree.merge(TrueRegion); + Tree.merge(FalseRegion); } - void VisitCallExpr(CallExpr *CE) { + void VisitCallExpr(const CallExpr *CE) { // C++11 [intro.execution]p15: // When calling a function [...], every value computation and side effect // associated with any argument expression, or with the postfix expression @@ -12472,12 +13189,13 @@ public: // expression or statement in the body of the function [and thus before // the value computation of its result]. SequencedSubexpression Sequenced(*this); - Base::VisitCallExpr(CE); + SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), + [&] { Base::VisitCallExpr(CE); }); // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. } - void VisitCXXConstructExpr(CXXConstructExpr *CCE) { + void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { // This is a call, so all subexpressions are sequenced before the result. SequencedSubexpression Sequenced(*this); @@ -12487,8 +13205,8 @@ public: // In C++11, list initializations are sequenced. SmallVector<SequenceTree::Seq, 32> Elts; SequenceTree::Seq Parent = Region; - for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(), - E = CCE->arg_end(); + for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(), + E = CCE->arg_end(); I != E; ++I) { Region = Tree.allocate(Parent); Elts.push_back(Region); @@ -12501,7 +13219,7 @@ public: Tree.merge(Elts[I]); } - void VisitInitListExpr(InitListExpr *ILE) { + void VisitInitListExpr(const InitListExpr *ILE) { if (!SemaRef.getLangOpts().CPlusPlus11) return VisitExpr(ILE); @@ -12509,8 +13227,9 @@ public: SmallVector<SequenceTree::Seq, 32> Elts; SequenceTree::Seq Parent = Region; for (unsigned I = 0; I < ILE->getNumInits(); ++I) { - Expr *E = ILE->getInit(I); - if (!E) continue; + const Expr *E = ILE->getInit(I); + if (!E) + continue; Region = Tree.allocate(Parent); Elts.push_back(Region); Visit(E); @@ -12525,11 +13244,11 @@ public: } // namespace -void Sema::CheckUnsequencedOperations(Expr *E) { - SmallVector<Expr *, 8> WorkList; +void Sema::CheckUnsequencedOperations(const Expr *E) { + SmallVector<const Expr *, 8> WorkList; WorkList.push_back(E); while (!WorkList.empty()) { - Expr *Item = WorkList.pop_back_val(); + const Expr *Item = WorkList.pop_back_val(); SequenceChecker(*this, Item, WorkList); } } @@ -12907,7 +13626,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (ND) DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, - PDiag(diag::note_array_index_out_of_bounds) + PDiag(diag::note_array_declared_here) << ND->getDeclName()); } @@ -14227,9 +14946,11 @@ void Sema::RefersToMemberWithReducedAlignment( bool AnyIsPacked = false; do { QualType BaseType = ME->getBase()->getType(); + if (BaseType->isDependentType()) + return; if (ME->isArrow()) BaseType = BaseType->getPointeeType(); - RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return; |
