Author: gbiv Date: Mon Dec 14 16:00:49 2015 New Revision: 255556 URL: http://llvm.org/viewvc/llvm-project?rev=255556&view=rev Log: [Sema] Make nullness warnings appear in C++.
Given the following code: int *_Nullable ptr; int *_Nonnull nn = ptr; ...In C, clang will warn you about `nn = ptr`, because you're assigning a nonnull pointer to a nullable pointer. In C++, clang issues no such warning. This patch helps ensure that clang doesn't ever miss an opportunity to complain about C++ code. N.B. Though this patch has a differential revision link, the actual review took place over email. Differential Revision: http://reviews.llvm.org/D14938 Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/Sema/nullability.c cfe/trunk/test/SemaCXX/nullability.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=255556&r1=255555&r2=255556&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Mon Dec 14 16:00:49 2015 @@ -3511,6 +3511,11 @@ public: void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); + /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a + /// _Nonnull one. + void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, + SourceLocation Loc); + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=255556&r1=255555&r2=255556&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Mon Dec 14 16:00:49 2015 @@ -349,6 +349,20 @@ void Sema::PrintStats() const { AnalysisWarnings.PrintStats(); } +void Sema::diagnoseNullableToNonnullConversion(QualType DstType, + QualType SrcType, + SourceLocation Loc) { + Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context); + if (!ExprNullability || *ExprNullability != NullabilityKind::Nullable) + return; + + Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context); + if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull) + return; + + Diag(Loc, diag::warn_nullability_lost) << SrcType << 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. @@ -372,18 +386,7 @@ 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; - } - } - } - } + diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getLocStart()); QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=255556&r1=255555&r2=255556&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Dec 14 16:00:49 2015 @@ -3118,6 +3118,7 @@ Sema::PerformImplicitConversion(Expr *Fr ToType = ToAtomic->getValueType(); } + QualType InitialFromType = FromType; // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: @@ -3488,6 +3489,12 @@ Sema::PerformImplicitConversion(Expr *Fr VK_RValue, nullptr, CCK).get(); } + // If this conversion sequence succeeded and involved implicitly converting a + // _Nullable type to a _Nonnull one, complain. + if (CCK == CCK_ImplicitConversion) + diagnoseNullableToNonnullConversion(ToType, InitialFromType, + From->getLocStart()); + return From; } Modified: cfe/trunk/test/Sema/nullability.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/nullability.c?rev=255556&r1=255555&r2=255556&view=diff ============================================================================== --- cfe/trunk/test/Sema/nullability.c (original) +++ cfe/trunk/test/Sema/nullability.c Mon Dec 14 16:00:49 2015 @@ -112,4 +112,7 @@ _Nonnull int *returns_int_ptr(int x) { 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'}} + b = ptr; // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}} + + accepts_nonnull_1(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=255556&r1=255555&r2=255556&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/nullability.cpp (original) +++ cfe/trunk/test/SemaCXX/nullability.cpp Mon Dec 14 16:00:49 2015 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion #if __has_feature(nullability) #else @@ -67,3 +67,33 @@ void test_accepts_nonnull_null_pointer_l } template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}} + +void TakeNonnull(void *_Nonnull); +// Check different forms of assignment to a nonull type from a nullable one. +void AssignAndInitNonNull() { + void *_Nullable nullable; + void *_Nonnull p(nullable); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p2{nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p3 = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p4 = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull nonnull; + nonnull = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + nonnull = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + + TakeNonnull(nullable); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}} + TakeNonnull(nonnull); // OK +} + +void *_Nullable ReturnNullable(); + +void AssignAndInitNonNullFromFn() { + void *_Nonnull p(ReturnNullable()); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p2{ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p3 = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull p4 = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + void *_Nonnull nonnull; + nonnull = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + nonnull = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} + + TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits