[PATCH] D14938: Fix implicit conversion from _Nullable to _Nonnull warnings in C++
Justin Bogner via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 14 13:20:18 PST 2015
George Burgess IV via cfe-commits <cfe-commits at lists.llvm.org> writes:
> george.burgess.iv created this revision.
> george.burgess.iv added a reviewer: doug.gregor.
> george.burgess.iv added subscribers: cfe-commits, doug.gregor.
>
> Currently, code like this compiles cleanly in C++, but with warnings
> (as it should) in C:
Are there already tests in place for the C version? I assume so, but
please double check.
>
> ```
> int foo() {
> void *_Nullable p;
> void *_Nonnull n = p;
> }
> ```
>
> This patch makes us emit the appropriate warnings in C++.
LGTM with a couple of nits, below.
> @doug.gregor: `arc` said you would be best to review this; if you're
> unable to, I'm happy to ping others. :)
>
> http://reviews.llvm.org/D14938
>
> Files:
> include/clang/Sema/Sema.h
> lib/Sema/Sema.cpp
> lib/Sema/SemaExpr.cpp
> lib/Sema/SemaExprCXX.cpp
> test/SemaCXX/nullability.cpp
>
> Index: test/SemaCXX/nullability.cpp
> ===================================================================
> --- test/SemaCXX/nullability.cpp
> +++ test/SemaCXX/nullability.cpp
> @@ -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 @@
> }
>
> 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}}
> +}
> Index: lib/Sema/SemaExprCXX.cpp
> ===================================================================
> --- lib/Sema/SemaExprCXX.cpp
> +++ lib/Sema/SemaExprCXX.cpp
> @@ -3118,6 +3118,7 @@
> ToType = ToAtomic->getValueType();
> }
>
> + QualType InitialFromType = FromType;
> // Perform the first implicit conversion.
> switch (SCS.First) {
> case ICK_Identity:
> @@ -3488,6 +3489,12 @@
> 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;
> }
>
> Index: lib/Sema/SemaExpr.cpp
> ===================================================================
> --- lib/Sema/SemaExpr.cpp
> +++ lib/Sema/SemaExpr.cpp
> @@ -11823,8 +11823,8 @@
>
> switch (ConvTy) {
> case Compatible:
> - DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
> - return false;
> + DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
> + return false;
This looks unrelated / please commit formatting cleanup separately.
>
> case PointerToInt:
> DiagKind = diag::ext_typecheck_convert_pointer_int;
> Index: lib/Sema/Sema.cpp
> ===================================================================
> --- lib/Sema/Sema.cpp
> +++ lib/Sema/Sema.cpp
> @@ -349,6 +349,16 @@
> AnalysisWarnings.PrintStats();
> }
>
> +void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
> + QualType SrcType,
> + SourceLocation Loc) {
> + if (auto ExprNullability = SrcType->getNullability(Context))
> + if (*ExprNullability == NullabilityKind::Nullable)
> + if (auto TypeNullability = DstType->getNullability(Context))
> + if (*TypeNullability == NullabilityKind::NonNull)
> + Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
> +}
This might be more readable with an early return or two. If it doesn't
seem any more readable to you it's fine as is though.
> +
> /// 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 +382,7 @@
> 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);
> Index: include/clang/Sema/Sema.h
> ===================================================================
> --- include/clang/Sema/Sema.h
> +++ include/clang/Sema/Sema.h
> @@ -3505,6 +3505,11 @@
> 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);
> }
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list