ahatanak created this revision.
ahatanak added a reviewer: doug.gregor.
ahatanak added a subscriber: cfe-commits.
This patch makes clang issue a warning when a null constant is used in a
context where a non null expression is expected. For example:
```
int * _Nonnull p0 = 0; // warning expected here
int * _Nonnull p1;
int * _Nonnull p2 = c ? p1 : 0; // warning expected here
```
A new function Sema::diagnoseNullPtrToNonnullCast is defined, which checks
whether a null pointer constant is being cast to a _Nonnull pointer type, and
called before ImplicitCastExprs are created.
rdar://problem/24724255
rdar://problem/22074116
https://reviews.llvm.org/D22391
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp
test/Sema/nullability.c
test/SemaCXX/nullability.cpp
Index: test/SemaCXX/nullability.cpp
===================================================================
--- test/SemaCXX/nullability.cpp
+++ test/SemaCXX/nullability.cpp
@@ -54,16 +54,16 @@
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}}
+ accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ accepts_nonnull_2(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ (x->*accepts_nonnull_3)(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ accepts_nonnull_4(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ accepts_nonnull_5(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
}
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}}
+ FP(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
}
template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}}
Index: test/Sema/nullability.c
===================================================================
--- test/Sema/nullability.c
+++ test/Sema/nullability.c
@@ -106,15 +106,15 @@
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}}
+ accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull}}
+ accepts_nonnull_2(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull}}
+ accepts_nonnull_3(0); // expected-warning{{null passed to a callee that requires a non-null argument}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull}}
}
// 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 0; // expected-warning{{null returned from function that requires a non-null return value}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull}}
}
return (_Nonnull int *)0;
@@ -128,3 +128,9 @@
accepts_nonnull_1(ptr); // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
}
+
+void null_const_to_nonnull(int c) {
+ int * _Nonnull p0 = 0; // expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ int * _Nonnull p1;
+ int * _Nonnull p2 = c ? p1 : 0; // expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -709,6 +709,7 @@
E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
+ diagnoseNullPtrToNonnullCast(T, E, E->getExprLoc());
ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
nullptr, VK_RValue);
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -362,6 +362,17 @@
Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
}
+void Sema::diagnoseNullPtrToNonnullCast(QualType DstType, Expr *E,
+ SourceLocation Loc) {
+ if (!DstType->isPointerType() || CurContext->isDependentContext())
+ return;
+
+ if (Optional<NullabilityKind> Kind = DstType->getNullability(Context))
+ if (*Kind == NullabilityKind::NonNull &&
+ E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ Diag(Loc, diag::warn_null_const_to_nonnull) << DstType;
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.
@@ -401,6 +412,7 @@
}
}
+ diagnoseNullPtrToNonnullCast(Ty, E, E->getExprLoc());
return ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK);
}
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3601,6 +3601,11 @@
void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
SourceLocation Loc);
+ /// Warn if we're implicitly casting from a null pointer constant to a
+ /// _Nonnull pointer type.
+ void diagnoseNullPtrToNonnullCast(QualType DstType, Expr *E,
+ SourceLocation Loc);
+
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
return DelayedDiagnostics.push(pool);
}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -8482,6 +8482,10 @@
"type %1">,
InGroup<NullableToNonNullConversion>, DefaultIgnore;
+def warn_null_const_to_nonnull : Warning<
+ "implicitly casting a null constant to non-nullable pointer type %0">,
+ InGroup<NullableToNonNullConversion>, DefaultIgnore;
+
def err_nullability_cs_multilevel : Error<
"nullability keyword %0 cannot be applied to multi-level pointer type %1">;
def note_nullability_type_specifier : Note<
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits