diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 179 |
1 files changed, 124 insertions, 55 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 20140525bb3..f76727cad88 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1115,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()) { @@ -1190,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. @@ -1261,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]) { @@ -1270,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()); + } } } @@ -1287,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 @@ -1301,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) { @@ -1311,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); @@ -1345,9 +1415,9 @@ 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; } @@ -1356,13 +1426,14 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { QualType Ty; if (const auto *V = dyn_cast<VarDecl>(NDecl)) - Ty = V->getType(); + Ty = V->getType().getNonReferenceType(); else if (const auto *F = dyn_cast<FieldDecl>(NDecl)) - Ty = F->getType(); + Ty = F->getType().getNonReferenceType(); else return false; - if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType()) + if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() && + !Ty->isFunctionProtoType()) return false; VariadicCallType CallType; @@ -1373,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; @@ -1388,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; @@ -5680,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(); |