diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp | 1039 |
1 files changed, 864 insertions, 175 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 6ab957e..f76727c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -184,7 +184,7 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { return true; } - QualType ReturnTy = CE->getCallReturnType(); + QualType ReturnTy = CE->getCallReturnType(S.Context); QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() }; QualType BuiltinTy = S.Context.getFunctionType( ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo()); @@ -202,6 +202,28 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { return false; } +static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, + Scope::ScopeFlags NeededScopeFlags, + unsigned DiagID) { + // Scopes aren't available during instantiation. Fortunately, builtin + // functions cannot be template args so they cannot be formed through template + // instantiation. Therefore checking once during the parse is sufficient. + if (!SemaRef.ActiveTemplateInstantiations.empty()) + return false; + + Scope *S = SemaRef.getCurScope(); + while (S && !S->isSEHExceptScope()) + S = S->getParent(); + if (!S || !(S->getFlags() & NeededScopeFlags)) { + auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + SemaRef.Diag(TheCall->getExprLoc(), DiagID) + << DRE->getDecl()->getIdentifier(); + return true; + } + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -301,6 +323,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinSetjmp(TheCall)) return ExprError(); break; + case Builtin::BI_setjmp: + case Builtin::BI_setjmpex: + if (checkArgCount(*this, TheCall, 1)) + return true; + break; case Builtin::BI__builtin_classify_type: if (checkArgCount(*this, TheCall, 1)) return true; @@ -465,6 +492,35 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; + + 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: { + 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(); + + if (CheckCXXThrowOperand( + TheCall->getLocStart(), + Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()), + TheCall)) + return ExprError(); + + TheCall->setType(Context.VoidPtrTy); + break; + } // Since the target specific builtins for each arch overlap, only check those @@ -490,11 +546,21 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::systemz: + if (CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; default: break; } @@ -557,7 +623,10 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, case NeonTypeFlags::Poly16: return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; case NeonTypeFlags::Poly64: - return Context.UnsignedLongTy; + if (IsInt64Long) + return Context.UnsignedLongTy; + else + return Context.UnsignedLongLongTy; case NeonTypeFlags::Poly128: break; case NeonTypeFlags::Float16: @@ -767,6 +836,16 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); } + if (BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); + + if (BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -807,6 +886,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); } + if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, false); + + if (BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp) + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -839,15 +928,161 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return SemaBuiltinConstantArgRange(TheCall, i, l, u); } +bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + unsigned i = 0, l = 0, u = 0; + bool Is64BitBltin = BuiltinID == PPC::BI__builtin_divde || + BuiltinID == PPC::BI__builtin_divdeu || + BuiltinID == PPC::BI__builtin_bpermd; + bool IsTarget64Bit = Context.getTargetInfo() + .getTypeWidth(Context + .getTargetInfo() + .getIntPtrType()) == 64; + bool IsBltinExtDiv = BuiltinID == PPC::BI__builtin_divwe || + BuiltinID == PPC::BI__builtin_divweu || + BuiltinID == PPC::BI__builtin_divde || + BuiltinID == PPC::BI__builtin_divdeu; + + if (Is64BitBltin && !IsTarget64Bit) + return Diag(TheCall->getLocStart(), diag::err_64_bit_builtin_32_bit_tgt) + << TheCall->getSourceRange(); + + if ((IsBltinExtDiv && !Context.getTargetInfo().hasFeature("extdiv")) || + (BuiltinID == PPC::BI__builtin_bpermd && + !Context.getTargetInfo().hasFeature("bpermd"))) + return Diag(TheCall->getLocStart(), diag::err_ppc_builtin_only_on_pwr7) + << TheCall->getSourceRange(); + + switch (BuiltinID) { + default: return false; + case PPC::BI__builtin_altivec_crypto_vshasigmaw: + case PPC::BI__builtin_altivec_crypto_vshasigmad: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + 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; + case PPC::BI__builtin_tabortwc: + case PPC::BI__builtin_tabortdc: i = 0; l = 0; u = 31; break; + case PPC::BI__builtin_tabortwci: + case PPC::BI__builtin_tabortdci: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + } + return SemaBuiltinConstantArgRange(TheCall, i, l, u); +} + +bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + if (BuiltinID == SystemZ::BI__builtin_tabort) { + Expr *Arg = TheCall->getArg(0); + llvm::APSInt AbortCode(32); + if (Arg->isIntegerConstantExpr(AbortCode, Context) && + AbortCode.getSExtValue() >= 0 && AbortCode.getSExtValue() < 256) + return Diag(Arg->getLocStart(), diag::err_systemz_invalid_tabort_code) + << Arg->getSourceRange(); + } + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: return false; + case SystemZ::BI__builtin_s390_lcbb: i = 1; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_verimb: + case SystemZ::BI__builtin_s390_verimh: + case SystemZ::BI__builtin_s390_verimf: + case SystemZ::BI__builtin_s390_verimg: i = 3; l = 0; u = 255; break; + case SystemZ::BI__builtin_s390_vfaeb: + case SystemZ::BI__builtin_s390_vfaeh: + case SystemZ::BI__builtin_s390_vfaef: + case SystemZ::BI__builtin_s390_vfaebs: + case SystemZ::BI__builtin_s390_vfaehs: + case SystemZ::BI__builtin_s390_vfaefs: + case SystemZ::BI__builtin_s390_vfaezb: + case SystemZ::BI__builtin_s390_vfaezh: + case SystemZ::BI__builtin_s390_vfaezf: + case SystemZ::BI__builtin_s390_vfaezbs: + case SystemZ::BI__builtin_s390_vfaezhs: + case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vfidb: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; + case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vsldb: i = 2; l = 0; u = 15; break; + case SystemZ::BI__builtin_s390_vstrcb: + case SystemZ::BI__builtin_s390_vstrch: + case SystemZ::BI__builtin_s390_vstrcf: + case SystemZ::BI__builtin_s390_vstrczb: + case SystemZ::BI__builtin_s390_vstrczh: + case SystemZ::BI__builtin_s390_vstrczf: + case SystemZ::BI__builtin_s390_vstrcbs: + case SystemZ::BI__builtin_s390_vstrchs: + case SystemZ::BI__builtin_s390_vstrcfs: + case SystemZ::BI__builtin_s390_vstrczbs: + case SystemZ::BI__builtin_s390_vstrczhs: + case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break; + } + return SemaBuiltinConstantArgRange(TheCall, i, l, u); +} + bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; 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_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_cmpb128_mask: + case X86::BI__builtin_ia32_cmpw128_mask: + case X86::BI__builtin_ia32_cmpd128_mask: + case X86::BI__builtin_ia32_cmpq128_mask: + case X86::BI__builtin_ia32_cmpb256_mask: + case X86::BI__builtin_ia32_cmpw256_mask: + case X86::BI__builtin_ia32_cmpd256_mask: + case X86::BI__builtin_ia32_cmpq256_mask: + case X86::BI__builtin_ia32_cmpb512_mask: + case X86::BI__builtin_ia32_cmpw512_mask: + case X86::BI__builtin_ia32_cmpd512_mask: + case X86::BI__builtin_ia32_cmpq512_mask: + case X86::BI__builtin_ia32_ucmpb128_mask: + case X86::BI__builtin_ia32_ucmpw128_mask: + case X86::BI__builtin_ia32_ucmpd128_mask: + case X86::BI__builtin_ia32_ucmpq128_mask: + case X86::BI__builtin_ia32_ucmpb256_mask: + case X86::BI__builtin_ia32_ucmpw256_mask: + case X86::BI__builtin_ia32_ucmpd256_mask: + case X86::BI__builtin_ia32_ucmpq256_mask: + 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_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_roundss: + case X86::BI__builtin_ia32_roundsd: 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: i = 2; l = 0; u = 31; break; + case X86::BI__builtin_ia32_cmpsd: + case X86::BI__builtin_ia32_cmpps256: + case X86::BI__builtin_ia32_cmppd256: + 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; } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -880,6 +1115,13 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// \brief Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { + // If the expression has non-null type, it doesn't evaluate to null. + if (auto nullability + = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) { + if (*nullability == NullabilityKind::NonNull) + return false; + } + // As a special case, transparent unions initialized with zero are // considered null for the purposes of the nonnull attribute. if (const RecordType *UT = Expr->getType()->getAsUnionType()) { @@ -955,56 +1197,111 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, } } +/// Determine whether the given type has a non-null nullability annotation. +static bool isNonNullType(ASTContext &ctx, QualType type) { + if (auto nullability = type->getNullability(ctx)) + return *nullability == NullabilityKind::NonNull; + + return false; +} + static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, + const FunctionProtoType *Proto, ArrayRef<const Expr *> Args, SourceLocation CallSiteLoc) { + assert((FDecl || Proto) && "Need a function declaration or prototype"); + // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; - for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { - if (!NonNull->args_size()) { - // Easy case: all pointer arguments are nonnull. - for (const auto *Arg : Args) - if (S.isValidPointerAttrType(Arg->getType())) - CheckNonNullArgument(S, Arg, CallSiteLoc); - return; - } + if (FDecl) { + // Handle the nonnull attribute on the function/method declaration itself. + for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { + if (!NonNull->args_size()) { + // Easy case: all pointer arguments are nonnull. + for (const auto *Arg : Args) + if (S.isValidPointerAttrType(Arg->getType())) + CheckNonNullArgument(S, Arg, CallSiteLoc); + return; + } - for (unsigned Val : NonNull->args()) { - if (Val >= Args.size()) - continue; - if (NonNullArgs.empty()) - NonNullArgs.resize(Args.size()); - NonNullArgs.set(Val); + for (unsigned Val : NonNull->args()) { + if (Val >= Args.size()) + continue; + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + NonNullArgs.set(Val); + } } } - // Check the attributes on the parameters. - ArrayRef<ParmVarDecl*> parms; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) - parms = FD->parameters(); - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl)) - parms = MD->parameters(); - - unsigned ArgIndex = 0; - for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); - I != E; ++I, ++ArgIndex) { - const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>() || - (ArgIndex < NonNullArgs.size() && NonNullArgs[ArgIndex])) - CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); + if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) { + // Handle the nonnull attribute on the parameters of the + // function/method. + ArrayRef<ParmVarDecl*> parms; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) + parms = FD->parameters(); + else + parms = cast<ObjCMethodDecl>(FDecl)->parameters(); + + unsigned ParamIndex = 0; + for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); + I != E; ++I, ++ParamIndex) { + const ParmVarDecl *PVD = *I; + if (PVD->hasAttr<NonNullAttr>() || + isNonNullType(S.Context, PVD->getType())) { + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + + NonNullArgs.set(ParamIndex); + } + } + } else { + // If we have a non-function, non-method declaration but no + // function prototype, try to dig out the function prototype. + if (!Proto) { + if (const ValueDecl *VD = dyn_cast<ValueDecl>(FDecl)) { + QualType type = VD->getType().getNonReferenceType(); + if (auto pointerType = type->getAs<PointerType>()) + type = pointerType->getPointeeType(); + else if (auto blockType = type->getAs<BlockPointerType>()) + type = blockType->getPointeeType(); + // FIXME: data member pointers? + + // Dig out the function prototype, if there is one. + Proto = type->getAs<FunctionProtoType>(); + } + } + + // Fill in non-null argument information from the nullability + // information on the parameter types (if we have them). + if (Proto) { + unsigned Index = 0; + for (auto paramType : Proto->getParamTypes()) { + if (isNonNullType(S.Context, paramType)) { + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + + NonNullArgs.set(Index); + } + + ++Index; + } + } } - // In case this is a variadic call, check any remaining arguments. - for (/**/; ArgIndex < NonNullArgs.size(); ++ArgIndex) + // Check for non-null arguments. + for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); + ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); + } } /// Handles the checks for format strings, non-POD arguments to vararg /// functions, and NULL arguments passed to non-NULL parameters. -void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, - unsigned NumParams, bool IsMemberFunction, +void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, + ArrayRef<const Expr *> Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType) { // FIXME: We should check as much as we can in the template definition. @@ -1026,6 +1323,13 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, // Refuse POD arguments that weren't caught by the format string // checks above. if (CallType != VariadicDoesNotApply) { + unsigned NumParams = Proto ? Proto->getNumParams() + : FDecl && isa<FunctionDecl>(FDecl) + ? cast<FunctionDecl>(FDecl)->getNumParams() + : FDecl && isa<ObjCMethodDecl>(FDecl) + ? cast<ObjCMethodDecl>(FDecl)->param_size() + : 0; + for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { @@ -1035,12 +1339,14 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, } } - if (FDecl) { - CheckNonNullArguments(*this, FDecl, Args, Loc); + if (FDecl || Proto) { + CheckNonNullArguments(*this, FDecl, Proto, Args, Loc); // Type safety checking. - for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) - CheckArgumentWithTypeTag(I, Args.data()); + if (FDecl) { + for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) + CheckArgumentWithTypeTag(I, Args.data()); + } } } @@ -1052,8 +1358,8 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, SourceLocation Loc) { VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; - checkCall(FDecl, Args, Proto->getNumParams(), - /*IsMemberFunction=*/true, Loc, SourceRange(), CallType); + checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(), + CallType); } /// CheckFunctionCall - Check a direct function call for various correctness @@ -1066,7 +1372,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, IsMemberOperatorCall; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, TheCall->getCallee()); - unsigned NumParams = Proto ? Proto->getNumParams() : 0; Expr** Args = TheCall->getArgs(); unsigned NumArgs = TheCall->getNumArgs(); if (IsMemberOperatorCall) { @@ -1076,7 +1381,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, ++Args; --NumArgs; } - checkCall(FDecl, llvm::makeArrayRef(Args, NumArgs), NumParams, + checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs), IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -1110,21 +1415,25 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; - checkCall(Method, Args, Method->param_size(), - /*IsMemberFunction=*/false, - lbrac, Method->getSourceRange(), CallType); + checkCall(Method, nullptr, Args, + /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), + CallType); return false; } bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { - const VarDecl *V = dyn_cast<VarDecl>(NDecl); - if (!V) + QualType Ty; + if (const auto *V = dyn_cast<VarDecl>(NDecl)) + Ty = V->getType().getNonReferenceType(); + else if (const auto *F = dyn_cast<FieldDecl>(NDecl)) + Ty = F->getType().getNonReferenceType(); + else return false; - QualType Ty = V->getType(); - if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType()) + if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() && + !Ty->isFunctionProtoType()) return false; VariadicCallType CallType; @@ -1135,11 +1444,10 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, } else { // Ty->isFunctionPointerType() CallType = VariadicFunction; } - unsigned NumParams = Proto ? Proto->getNumParams() : 0; - checkCall(NDecl, llvm::makeArrayRef(TheCall->getArgs(), - TheCall->getNumArgs()), - NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), + checkCall(NDecl, Proto, + llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), + /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; @@ -1150,11 +1458,9 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto, TheCall->getCallee()); - unsigned NumParams = Proto ? Proto->getNumParams() : 0; - - checkCall(/*FDecl=*/nullptr, + checkCall(/*FDecl=*/nullptr, Proto, llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), - NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), + /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; @@ -1220,9 +1526,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // M is C if C is an integer, and ptrdiff_t if C is a pointer, and // the int parameters are for orderings. - assert(AtomicExpr::AO__c11_atomic_init == 0 && - AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load - && "need to update code for modified C11 atomics"); + static_assert(AtomicExpr::AO__c11_atomic_init == 0 && + AtomicExpr::AO__c11_atomic_fetch_xor + 1 == + AtomicExpr::AO__atomic_load, + "need to update code for modified C11 atomics"); bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init && Op <= AtomicExpr::AO__c11_atomic_fetch_xor; bool IsN = Op == AtomicExpr::AO__atomic_load_n || @@ -1385,6 +1692,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } + // 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. + ValType.removeLocalVolatile(); QualType ResultType = ValType; if (Form == Copy || Form == GNUXchg || Form == Init) ResultType = Context.VoidTy; @@ -2039,7 +2350,7 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { if (checkBuiltinArgument(*this, Call, 0)) return true; - static const struct { + const struct { unsigned ArgNo; QualType Type; } ArgumentTypes[] = { @@ -2286,7 +2597,7 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { if (Arg->isInstantiationDependent()) return false; if (Arg->HasSideEffects(Context)) - return Diag(Arg->getLocStart(), diag::warn_assume_side_effects) + Diag(Arg->getLocStart(), diag::warn_assume_side_effects) << Arg->getSourceRange() << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier(); @@ -2370,6 +2681,107 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr +/// TheCall is an ARM/AArch64 special register string literal. +bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName) { + bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || + BuiltinID == ARM::BI__builtin_arm_wsr64 || + BuiltinID == ARM::BI__builtin_arm_rsr || + BuiltinID == ARM::BI__builtin_arm_rsrp || + BuiltinID == ARM::BI__builtin_arm_wsr || + BuiltinID == ARM::BI__builtin_arm_wsrp; + bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || + BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr || + BuiltinID == AArch64::BI__builtin_arm_rsrp || + BuiltinID == AArch64::BI__builtin_arm_wsr || + BuiltinID == AArch64::BI__builtin_arm_wsrp; + assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check if the argument is a string literal. + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) + return Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the type of special register given. + StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); + SmallVector<StringRef, 6> Fields; + Reg.split(Fields, ":"); + + if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) + return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + + // If the string is the name of a register then we cannot check that it is + // valid here but if the string is of one the forms described in ACLE then we + // can check that the supplied fields are integers and within the valid + // ranges. + if (Fields.size() > 1) { + bool FiveFields = Fields.size() == 5; + + bool ValidString = true; + if (IsARMBuiltin) { + ValidString &= Fields[0].startswith_lower("cp") || + Fields[0].startswith_lower("p"); + if (ValidString) + Fields[0] = + Fields[0].drop_front(Fields[0].startswith_lower("cp") ? 2 : 1); + + ValidString &= Fields[2].startswith_lower("c"); + if (ValidString) + Fields[2] = Fields[2].drop_front(1); + + if (FiveFields) { + ValidString &= Fields[3].startswith_lower("c"); + if (ValidString) + Fields[3] = Fields[3].drop_front(1); + } + } + + SmallVector<int, 5> Ranges; + if (FiveFields) + Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 7, 15, 15}); + else + Ranges.append({15, 7, 15}); + + for (unsigned i=0; i<Fields.size(); ++i) { + int IntField; + ValidString &= !Fields[i].getAsInteger(10, IntField); + ValidString &= (IntField >= 0 && IntField <= Ranges[i]); + } + + if (!ValidString) + return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) + << Arg->getSourceRange(); + + } else if (IsAArch64Builtin && Fields.size() == 1) { + // If the register name is one of those that appear in the condition below + // and the special register builtin being used is one of the write builtins, + // then we require that the argument provided for writing to the register + // is an integer constant expression. This is because it will be lowered to + // an MSR (immediate) instruction, so we need to know the immediate at + // compile time. + if (TheCall->getNumArgs() != 2) + return false; + + std::string RegLower = Reg.lower(); + if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" && + RegLower != "pan" && RegLower != "uao") + return false; + + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + return false; +} + /// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. @@ -2604,6 +3016,7 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { .Case("strfmon", FST_Strfmon) .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) .Case("freebsd_kprintf", FST_FreeBSDKPrintf) + .Case("os_trace", FST_OSTrace) .Default(FST_Unknown); } @@ -3074,10 +3487,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, if (InFunctionCall) { const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); D << StringRange; - for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end(); - I != E; ++I) { - D << *I; - } + D << FixIt; } else { S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag) << ArgumentExpr->getSourceRange(); @@ -3087,10 +3497,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, diag::note_format_string_defined); Note << StringRange; - for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end(); - I != E; ++I) { - Note << *I; - } + Note << FixIt; } } @@ -3600,8 +4007,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - if (AT.matchesType(S.Context, ExprTy)) + analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy); + + if (match == analyze_printf::ArgType::Match) { return true; + } // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array @@ -3696,16 +4106,18 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { + unsigned diag = diag::warn_format_conversion_argument_type_mismatch; + if (match == analyze_format_string::ArgType::NoMatchPedantic) { + diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + } // In this case, the specifier is wrong and should be changed to match // the argument. - EmitFormatDiagnostic( - S.PDiag(diag::warn_format_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum - << E->getSourceRange(), - E->getLocStart(), - /*IsStringLocation*/false, - SpecRange, - FixItHint::CreateReplacement(SpecRange, os.str())); + EmitFormatDiagnostic(S.PDiag(diag) + << AT.getRepresentativeTypeName(S.Context) + << IntendedTy << IsEnum << E->getSourceRange(), + E->getLocStart(), + /*IsStringLocation*/ false, SpecRange, + FixItHint::CreateReplacement(SpecRange, os.str())); } else { // The canonical type for formatting this value is different from the @@ -3779,15 +4191,18 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // arguments here. switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: - case Sema::VAK_ValidInCXX11: + case Sema::VAK_ValidInCXX11: { + unsigned diag = diag::warn_format_conversion_argument_type_mismatch; + if (match == analyze_printf::ArgType::NoMatchPedantic) { + diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + } + EmitFormatDiagnostic( - S.PDiag(diag::warn_format_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum - << CSR - << E->getSourceRange(), - E->getLocStart(), /*IsStringLocation*/false, CSR); + S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy + << IsEnum << CSR << E->getSourceRange(), + E->getLocStart(), /*IsStringLocation*/ false, CSR); break; - + } case Sema::VAK_Undefined: case Sema::VAK_MSVCUndefined: EmitFormatDiagnostic( @@ -3919,13 +4334,13 @@ bool CheckScanfHandler::HandleScanfSpecifier( FixItHint::CreateRemoval(R)); } } - + if (!FS.consumesDataArgument()) { // FIXME: Technically specifying a precision or field width here // makes no sense. Worth issuing a warning at some point. return true; } - + // Consume the argument. unsigned argIndex = FS.getArgIndex(); if (argIndex < NumDataArgs) { @@ -3934,7 +4349,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( // function if we encounter some other error. CoveredArgs.set(argIndex); } - + // Check the length modifier is valid with the given conversion specifier. if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, @@ -3951,47 +4366,57 @@ bool CheckScanfHandler::HandleScanfSpecifier( // The remaining checks depend on the data arguments. if (HasVAListArg) return true; - + if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; - + // Check that the argument type matches the format specifier. const Expr *Ex = getDataArg(argIndex); if (!Ex) return true; const analyze_format_string::ArgType &AT = FS.getArgType(S.Context); - if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) { - ScanfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(Ex->getType(), - Ex->IgnoreImpCasts()->getType(), - S.getLangOpts(), S.Context); - - if (success) { - // Get the fix string from the fixed format specifier. - SmallString<128> buf; - llvm::raw_svector_ostream os(buf); - fixedFS.toString(os); - EmitFormatDiagnostic( - S.PDiag(diag::warn_format_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false - << Ex->getSourceRange(), + if (!AT.isValid()) { + return true; + } + + analyze_format_string::ArgType::MatchKind match = + AT.matchesType(S.Context, Ex->getType()); + if (match == analyze_format_string::ArgType::Match) { + return true; + } + + ScanfSpecifier fixedFS = FS; + bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), + S.getLangOpts(), S.Context); + + unsigned diag = diag::warn_format_conversion_argument_type_mismatch; + if (match == analyze_format_string::ArgType::NoMatchPedantic) { + diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + } + + if (success) { + // Get the fix string from the fixed format specifier. + SmallString<128> buf; + llvm::raw_svector_ostream os(buf); + fixedFS.toString(os); + + EmitFormatDiagnostic( + S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) + << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), - /*IsStringLocation*/false, + /*IsStringLocation*/ false, getSpecifierRange(startSpecifier, specifierLen), FixItHint::CreateReplacement( - getSpecifierRange(startSpecifier, specifierLen), - os.str())); - } else { - EmitFormatDiagnostic( - S.PDiag(diag::warn_format_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false - << Ex->getSourceRange(), - Ex->getLocStart(), - /*IsStringLocation*/false, - getSpecifierRange(startSpecifier, specifierLen)); - } + getSpecifierRange(startSpecifier, specifierLen), os.str())); + } else { + EmitFormatDiagnostic(S.PDiag(diag) + << AT.getRepresentativeTypeName(S.Context) + << Ex->getType() << false << Ex->getSourceRange(), + Ex->getLocStart(), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); } return true; @@ -4046,9 +4471,9 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } if (Type == FST_Printf || Type == FST_NSString || - Type == FST_FreeBSDKPrintf) { + Type == FST_FreeBSDKPrintf || Type == FST_OSTrace) { CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - numDataArgs, (Type == FST_NSString), + numDataArgs, (Type == FST_NSString || Type == FST_OSTrace), Str, HasVAListArg, Args, format_idx, inFunctionCall, CallType, CheckedVarArgs); @@ -4533,7 +4958,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, /// \brief If E is a sizeof expression, returns its argument expression, /// otherwise returns NULL. -static const Expr *getSizeOfExprArg(const Expr* E) { +static const Expr *getSizeOfExprArg(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) @@ -4543,7 +4968,7 @@ static const Expr *getSizeOfExprArg(const Expr* E) { } /// \brief If E is a sizeof expression, returns its argument type. -static QualType getSizeOfArgType(const Expr* E) { +static QualType getSizeOfArgType(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) if (SizeOf->getKind() == clang::UETT_SizeOf) @@ -4589,8 +5014,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); QualType DestTy = Dest->getType(); + QualType PointeeTy; if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { - QualType PointeeTy = DestPtrTy->getPointeeType(); + PointeeTy = DestPtrTy->getPointeeType(); // Never warn about void type pointers. This can be used to suppress // false positives. @@ -4670,47 +5096,53 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, break; } } + } else if (DestTy->isArrayType()) { + PointeeTy = DestTy; + } - // Always complain about dynamic classes. - bool IsContained; - if (const CXXRecordDecl *ContainedRD = - getContainedDynamicClass(PointeeTy, IsContained)) { - - unsigned OperationType = 0; - // "overwritten" if we're warning about the destination for any call - // but memcmp; otherwise a verb appropriate to the call. - if (ArgIdx != 0 || BId == Builtin::BImemcmp) { - if (BId == Builtin::BImemcpy) - OperationType = 1; - else if(BId == Builtin::BImemmove) - OperationType = 2; - else if (BId == Builtin::BImemcmp) - OperationType = 3; - } - - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_dyn_class_memaccess) - << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) - << FnName << IsContained << ContainedRD << OperationType - << Call->getCallee()->getSourceRange()); - } else if (PointeeTy.hasNonTrivialObjCLifetime() && - BId != Builtin::BImemset) - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_arc_object_memaccess) - << ArgIdx << FnName << PointeeTy - << Call->getCallee()->getSourceRange()); - else - continue; + if (PointeeTy == QualType()) + continue; + // Always complain about dynamic classes. + bool IsContained; + if (const CXXRecordDecl *ContainedRD = + getContainedDynamicClass(PointeeTy, IsContained)) { + + unsigned OperationType = 0; + // "overwritten" if we're warning about the destination for any call + // but memcmp; otherwise a verb appropriate to the call. + if (ArgIdx != 0 || BId == Builtin::BImemcmp) { + if (BId == Builtin::BImemcpy) + OperationType = 1; + else if(BId == Builtin::BImemmove) + OperationType = 2; + else if (BId == Builtin::BImemcmp) + OperationType = 3; + } + DiagRuntimeBehavior( Dest->getExprLoc(), Dest, - PDiag(diag::note_bad_memaccess_silence) - << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); - break; - } + PDiag(diag::warn_dyn_class_memaccess) + << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) + << FnName << IsContained << ContainedRD << OperationType + << Call->getCallee()->getSourceRange()); + } else if (PointeeTy.hasNonTrivialObjCLifetime() && + BId != Builtin::BImemset) + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_arc_object_memaccess) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); + else + continue; + + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::note_bad_memaccess_silence) + << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + break; } + } // A little helper routine: ignore addition and subtraction of integer literals. @@ -5316,7 +5748,8 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); // Check if the return value is null but should not be. - if (Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs) && + if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || + (!isObjCMethod && isNonNullType(Context, lhsType))) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_null_ret) << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); @@ -5861,7 +6294,7 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, // TODO: Investigate using GetExprRange() to get tighter bounds // on the bit ranges. QualType OtherT = Other->getType(); - if (const AtomicType *AT = dyn_cast<AtomicType>(OtherT)) + if (const auto *AT = OtherT->getAs<AtomicType>()) OtherT = AT->getValueType(); IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); unsigned OtherWidth = OtherRange.Width; @@ -6705,8 +7138,11 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { E = POE->getResultExpr(); } - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) - return AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { + if (OVE->getSourceExpr()) + AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); + return; + } // Skip past explicit casts. if (isa<ExplicitCastExpr>(E)) { @@ -6788,7 +7224,7 @@ static bool CheckForReference(Sema &SemaRef, const Expr *E, if (!M->getMemberDecl()->getType()->isReferenceType()) return false; } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) { - if (!Call->getCallReturnType()->isReferenceType()) + if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType()) return false; FD = Call->getDirectCallee(); } else { @@ -7533,6 +7969,35 @@ void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc); } +static void diagnoseArrayStarInParamType(Sema &S, QualType PType, + SourceLocation Loc) { + if (!PType->isVariablyModifiedType()) + return; + if (const auto *PointerTy = dyn_cast<PointerType>(PType)) { + diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc); + return; + } + if (const auto *ReferenceTy = dyn_cast<ReferenceType>(PType)) { + diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc); + return; + } + if (const auto *ParenTy = dyn_cast<ParenType>(PType)) { + diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc); + return; + } + + const ArrayType *AT = S.Context.getAsArrayType(PType); + if (!AT) + return; + + if (AT->getSizeModifier() != ArrayType::Star) { + diagnoseArrayStarInParamType(S, AT->getElementType(), Loc); + return; + } + + S.Diag(Loc, diag::err_array_star_in_function_definition); +} + /// CheckParmsForFunctionDef - Check that the parameters of the given /// function are appropriate for the definition of a function. This /// takes care of any checks that cannot be performed on the @@ -7571,15 +8036,9 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P, // notation in their sequences of declarator specifiers to specify // variable length array types. QualType PType = Param->getOriginalType(); - while (const ArrayType *AT = Context.getAsArrayType(PType)) { - if (AT->getSizeModifier() == ArrayType::Star) { - // FIXME: This diagnostic should point the '[*]' if source-location - // information is added for it. - Diag(Param->getLocation(), diag::err_array_star_in_function_definition); - break; - } - PType= AT->getElementType(); - } + // FIXME: This diagnostic should point the '[*]' if source-location + // information is added for it. + diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); // MSVC destroys objects passed by value in the callee. Therefore a // function definition which takes such a parameter must be able to call the @@ -8097,6 +8556,236 @@ static bool isSetterLikeSelector(Selector sel) { return !isLowercase(str.front()); } +static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S, + ObjCMessageExpr *Message) { + if (S.NSMutableArrayPointer.isNull()) { + IdentifierInfo *NSMutableArrayId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableArray); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableArrayId, + Message->getLocStart(), + Sema::LookupOrdinaryName); + ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (!InterfaceDecl) { + return None; + } + QualType NSMutableArrayObject = + S.Context.getObjCInterfaceType(InterfaceDecl); + S.NSMutableArrayPointer = + S.Context.getObjCObjectPointerType(NSMutableArrayObject); + } + + if (S.NSMutableArrayPointer != Message->getReceiverType()) { + return None; + } + + Selector Sel = Message->getSelector(); + + Optional<NSAPI::NSArrayMethodKind> MKOpt = + S.NSAPIObj->getNSArrayMethodKind(Sel); + if (!MKOpt) { + return None; + } + + NSAPI::NSArrayMethodKind MK = *MKOpt; + + switch (MK) { + case NSAPI::NSMutableArr_addObject: + case NSAPI::NSMutableArr_insertObjectAtIndex: + case NSAPI::NSMutableArr_setObjectAtIndexedSubscript: + return 0; + case NSAPI::NSMutableArr_replaceObjectAtIndex: + return 1; + + default: + return None; + } + + return None; +} + +static +Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S, + ObjCMessageExpr *Message) { + + if (S.NSMutableDictionaryPointer.isNull()) { + IdentifierInfo *NSMutableDictionaryId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableDictionary); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableDictionaryId, + Message->getLocStart(), + Sema::LookupOrdinaryName); + ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (!InterfaceDecl) { + return None; + } + QualType NSMutableDictionaryObject = + S.Context.getObjCInterfaceType(InterfaceDecl); + S.NSMutableDictionaryPointer = + S.Context.getObjCObjectPointerType(NSMutableDictionaryObject); + } + + if (S.NSMutableDictionaryPointer != Message->getReceiverType()) { + return None; + } + + Selector Sel = Message->getSelector(); + + Optional<NSAPI::NSDictionaryMethodKind> MKOpt = + S.NSAPIObj->getNSDictionaryMethodKind(Sel); + if (!MKOpt) { + return None; + } + + NSAPI::NSDictionaryMethodKind MK = *MKOpt; + + switch (MK) { + case NSAPI::NSMutableDict_setObjectForKey: + case NSAPI::NSMutableDict_setValueForKey: + case NSAPI::NSMutableDict_setObjectForKeyedSubscript: + return 0; + + default: + return None; + } + + return None; +} + +static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { + + ObjCInterfaceDecl *InterfaceDecl; + if (S.NSMutableSetPointer.isNull()) { + IdentifierInfo *NSMutableSetId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableSet); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableSetId, + Message->getLocStart(), + Sema::LookupOrdinaryName); + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (InterfaceDecl) { + QualType NSMutableSetObject = + S.Context.getObjCInterfaceType(InterfaceDecl); + S.NSMutableSetPointer = + S.Context.getObjCObjectPointerType(NSMutableSetObject); + } + } + + if (S.NSCountedSetPointer.isNull()) { + IdentifierInfo *NSCountedSetId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSCountedSet); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSCountedSetId, + Message->getLocStart(), + Sema::LookupOrdinaryName); + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (InterfaceDecl) { + QualType NSCountedSetObject = + S.Context.getObjCInterfaceType(InterfaceDecl); + S.NSCountedSetPointer = + S.Context.getObjCObjectPointerType(NSCountedSetObject); + } + } + + if (S.NSMutableOrderedSetPointer.isNull()) { + IdentifierInfo *NSOrderedSetId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableOrderedSet); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSOrderedSetId, + Message->getLocStart(), + Sema::LookupOrdinaryName); + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (InterfaceDecl) { + QualType NSOrderedSetObject = + S.Context.getObjCInterfaceType(InterfaceDecl); + S.NSMutableOrderedSetPointer = + S.Context.getObjCObjectPointerType(NSOrderedSetObject); + } + } + + QualType ReceiverType = Message->getReceiverType(); + + bool IsMutableSet = !S.NSMutableSetPointer.isNull() && + ReceiverType == S.NSMutableSetPointer; + bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() && + ReceiverType == S.NSMutableOrderedSetPointer; + bool IsCountedSet = !S.NSCountedSetPointer.isNull() && + ReceiverType == S.NSCountedSetPointer; + + if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) { + return None; + } + + Selector Sel = Message->getSelector(); + + Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel); + if (!MKOpt) { + return None; + } + + NSAPI::NSSetMethodKind MK = *MKOpt; + + switch (MK) { + case NSAPI::NSMutableSet_addObject: + case NSAPI::NSOrderedSet_setObjectAtIndex: + case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript: + case NSAPI::NSOrderedSet_insertObjectAtIndex: + return 0; + case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject: + return 1; + } + + return None; +} + +void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { + if (!Message->isInstanceMessage()) { + return; + } + + Optional<int> ArgOpt; + + if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) && + !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) && + !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) { + return; + } + + int ArgIndex = *ArgOpt; + + Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts(); + if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) { + Receiver = OE->getSourceExpr()->IgnoreImpCasts(); + } + + Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts(); + if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) { + Arg = OE->getSourceExpr()->IgnoreImpCasts(); + } + + if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) { + if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) { + if (ReceiverRE->getDecl() == ArgRE->getDecl()) { + ValueDecl *Decl = ReceiverRE->getDecl(); + Diag(Message->getSourceRange().getBegin(), + diag::warn_objc_circular_container) + << Decl->getName(); + Diag(Decl->getLocation(), + diag::note_objc_circular_container_declared_here) + << Decl->getName(); + } + } + } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) { + if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) { + if (IvarRE->getDecl() == IvarArgRE->getDecl()) { + ObjCIvarDecl *Decl = IvarRE->getDecl(); + Diag(Message->getSourceRange().getBegin(), + diag::warn_objc_circular_container) + << Decl->getName(); + Diag(Decl->getLocation(), + diag::note_objc_circular_container_declared_here) + << Decl->getName(); + } + } + } + +} + /// Check a message send to see if it's likely to cause a retain cycle. void Sema::checkRetainCycles(ObjCMessageExpr *msg) { // Only check instance methods whose selector looks like a setter. @@ -8281,7 +8970,7 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, // Get line numbers of statement and body. bool StmtLineInvalid; - unsigned StmtLine = SourceMgr.getSpellingLineNumber(StmtLoc, + unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc, &StmtLineInvalid); if (StmtLineInvalid) return false; |