r240153 - Diagnose unsafe uses of nil and __nonnull pointers.
Douglas Gregor
dgregor at apple.com
Fri Jun 19 11:13:19 PDT 2015
Author: dgregor
Date: Fri Jun 19 13:13:19 2015
New Revision: 240153
URL: http://llvm.org/viewvc/llvm-project?rev=240153&view=rev
Log:
Diagnose unsafe uses of nil and __nonnull pointers.
This generalizes the checking of null arguments to also work with
values of pointer-to-function, reference-to-function, and block
pointer type, using the nullability information within the underling
function prototype to extend non-null checking, and diagnoses returns
of 'nil' within a function with a __nonnull return type.
Note that we don't warn about nil returns from Objective-C methods,
because it's common for Objective-C methods to mimic the nil-swallowing
behavior of the receiver by checking ostensibly non-null parameters
and returning nil from otherwise non-null methods in that
case.
It also diagnoses (via a separate flag) conversions from nullable to
nonnull pointers. It's a separate flag because this warning can be noisy.
Added:
cfe/trunk/test/SemaObjC/nullability-arc.m
Modified:
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/Sema/non-null-warning.c
cfe/trunk/test/Sema/nullability.c
cfe/trunk/test/SemaCXX/nullability.cpp
cfe/trunk/test/SemaObjC/nullability.m
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Jun 19 13:13:19 2015
@@ -250,6 +250,7 @@ def ModuleConflict : DiagGroup<"module-c
def NewlineEOF : DiagGroup<"newline-eof">;
def Nullability : DiagGroup<"nullability">;
def NullabilityDeclSpec : DiagGroup<"nullability-declspec">;
+def NullableToNonNullConversion : DiagGroup<"nullable-to-nonnull-conversion">;
def NullArithmetic : DiagGroup<"null-arithmetic">;
def NullCharacter : DiagGroup<"null-character">;
def NullDereference : DiagGroup<"null-dereference">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 19 13:13:19 2015
@@ -7700,6 +7700,11 @@ def err_nullability_conflicting : Error<
"'%select{__nonnull|__nullable|__null_unspecified}0' conflicts with existing "
"specifier '%select{__nonnull|__nullable|__null_unspecified}1'">;
+def warn_nullability_lost : Warning<
+ "implicit conversion from nullable pointer %0 to non-nullable pointer "
+ "type %1">,
+ InGroup<NullableToNonNullConversion>, DefaultIgnore;
+
}
} // end of sema component.
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 19 13:13:19 2015
@@ -8580,9 +8580,10 @@ private:
const FunctionProtoType *Proto,
SourceLocation Loc);
- void checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args,
- unsigned NumParams, bool IsMemberFunction, SourceLocation Loc,
- SourceRange Range, VariadicCallType CallType);
+ void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
+ ArrayRef<const Expr *> Args, bool IsMemberFunction,
+ SourceLocation Loc, SourceRange Range,
+ VariadicCallType CallType);
bool CheckObjCString(Expr *Arg);
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Jun 19 13:13:19 2015
@@ -356,6 +356,19 @@ ExprResult Sema::ImpCastExprToType(Expr
assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
#endif
+ // Check whether we're implicitly casting from a nullable type to a nonnull
+ // type.
+ if (auto exprNullability = E->getType()->getNullability(Context)) {
+ if (*exprNullability == NullabilityKind::Nullable) {
+ if (auto typeNullability = Ty->getNullability(Context)) {
+ if (*typeNullability == NullabilityKind::NonNull) {
+ Diag(E->getLocStart(), diag::warn_nullability_lost)
+ << E->getType() << Ty;
+ }
+ }
+ }
+ }
+
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Jun 19 13:13:19 2015
@@ -1115,6 +1115,13 @@ bool Sema::getFormatStringInfo(const For
/// \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(Se
}
}
+/// 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, A
// 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, A
}
}
- 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(Function
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(FunctionDec
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(FunctionDec
++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(ObjCMetho
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 *N
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 *N
} 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 *N
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
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();
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jun 19 13:13:19 2015
@@ -11260,7 +11260,7 @@ Sema::CreateOverloadedBinOp(SourceLocati
if (Op == OO_Equal)
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
- checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc,
+ checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), OpLoc,
TheCall->getSourceRange(), VariadicDoesNotApply);
return MaybeBindToTemporary(TheCall);
Modified: cfe/trunk/test/Sema/non-null-warning.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/non-null-warning.c?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/test/Sema/non-null-warning.c (original)
+++ cfe/trunk/test/Sema/non-null-warning.c Fri Jun 19 13:13:19 2015
@@ -33,3 +33,10 @@ int *foo3(int * __nonnull x) { // expect
return 0;
}
+int * ret_nonnull() {
+ return 0; // expected-warning {{null returned from function that requires a non-null return value}}
+}
+
+int main () {
+ foo(0); // expected-warning {{null passed to a callee that requires a non-null argument}}
+}
Modified: cfe/trunk/test/Sema/nullability.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/nullability.c?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/test/Sema/nullability.c (original)
+++ cfe/trunk/test/Sema/nullability.c Fri Jun 19 13:13:19 2015
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-nullability-declspec %s -verify
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wnullable-to-nonnull-conversion -Wno-nullability-declspec %s -verify
#if __has_feature(nullability)
#else
@@ -85,3 +85,29 @@ void printing_nullability(void) {
int * __nullable * __nonnull iptrptr2;
float * *fptrptr2 = iptrptr2; // expected-warning{{incompatible pointer types initializing 'float **' with an expression of type 'int * __nullable * __nonnull'}}
}
+
+// Check passing null to a __nonnull argument.
+void accepts_nonnull_1(__nonnull int *ptr);
+void (*accepts_nonnull_2)(__nonnull int *ptr);
+void (^accepts_nonnull_3)(__nonnull int *ptr);
+
+void test_accepts_nonnull_null_pointer_literal() {
+ accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ accepts_nonnull_2(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ accepts_nonnull_3(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
+
+// Check returning nil from a __nonnull-returning function.
+__nonnull int *returns_int_ptr(int x) {
+ if (x) {
+ return 0; // expected-warning{{null returned from function that requires a non-null return value}}
+ }
+
+ return (__nonnull int *)0;
+}
+
+// Check nullable-to-nonnull conversions.
+void nullable_to_nonnull(__nullable int *ptr) {
+ int *a = ptr; // okay
+ __nonnull int *b = ptr; // expected-warning{{implicit conversion from nullable pointer 'int * __nullable' to non-nullable pointer type 'int * __nonnull'}}
+}
Modified: cfe/trunk/test/SemaCXX/nullability.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nullability.cpp?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nullability.cpp (original)
+++ cfe/trunk/test/SemaCXX/nullability.cpp Fri Jun 19 13:13:19 2015
@@ -40,3 +40,25 @@ struct AddNonNull2 {
// cannot apply to that specific dependent type.
typedef __nonnull AddNonNull<T> (*invalid4); // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'AddNonNull<T>'}}
};
+
+// Check passing null to a __nonnull argument.
+void (*accepts_nonnull_1)(__nonnull int *ptr);
+void (*& accepts_nonnull_2)(__nonnull int *ptr) = accepts_nonnull_1;
+void (X::* accepts_nonnull_3)(__nonnull int *ptr);
+void accepts_nonnull_4(__nonnull int *ptr);
+void (&accepts_nonnull_5)(__nonnull int *ptr) = accepts_nonnull_4;
+
+void test_accepts_nonnull_null_pointer_literal(X *x) {
+ accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ accepts_nonnull_2(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ (x->*accepts_nonnull_3)(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ accepts_nonnull_4(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+ accepts_nonnull_5(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
+
+template<void FP(__nonnull int*)>
+void test_accepts_nonnull_null_pointer_literal_template() {
+ FP(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
+
+template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}}
Added: cfe/trunk/test/SemaObjC/nullability-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullability-arc.m?rev=240153&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/nullability-arc.m (added)
+++ cfe/trunk/test/SemaObjC/nullability-arc.m Fri Jun 19 13:13:19 2015
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fobjc-arc -fsyntax-only -Woverriding-method-mismatch %s -verify
+
+__attribute__((objc_root_class))
+ at interface NSFoo
+ at end
+
+// ARC qualifiers stacked with nullability.
+void accepts_arc_qualified(NSFoo * __unsafe_unretained __nonnull obj) {
+ accepts_arc_qualified(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
Modified: cfe/trunk/test/SemaObjC/nullability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullability.m?rev=240153&r1=240152&r2=240153&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/nullability.m (original)
+++ cfe/trunk/test/SemaObjC/nullability.m Fri Jun 19 13:13:19 2015
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec %s -verify
+__attribute__((objc_root_class))
@interface NSFoo
+- (void)methodTakingIntPtr:(__nonnull int *)ptr;
+- (__nonnull int *)methodReturningIntPtr;
@end
// Nullability applies to all pointer types.
@@ -17,3 +20,14 @@ typedef __nonnull NSFoo * __nullable con
void testBlocksPrinting(NSFoo * __nullable (^bp)(int)) {
int *ip = bp; // expected-error{{'NSFoo * __nullable (^)(int)'}}
}
+void test_accepts_nonnull_null_pointer_literal(NSFoo *foo) {
+ [foo methodTakingIntPtr: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
+
+// Check returning nil from a __nonnull-returning method.
+ at implementation NSFoo
+- (void)methodTakingIntPtr:(__nonnull int *)ptr { }
+- (__nonnull int *)methodReturningIntPtr {
+ return 0; // no warning
+}
+ at end
More information about the cfe-commits
mailing list