Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8482,6 +8482,10 @@ "type %1">, InGroup, DefaultIgnore; +def warn_null_const_to_nonnull : Warning< + "implicitly casting a null constant to non-nullable pointer type %0">, + InGroup, 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< 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: 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 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: 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: 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: 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 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}}