forked from OSchip/llvm-project
[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 llvm-svn: 255556
This commit is contained in:
parent
fa54acedd1
commit
8d141e0120
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 *E, QualType Ty,
|
|||
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);
|
||||
|
|
|
@ -3118,6 +3118,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
|||
ToType = ToAtomic->getValueType();
|
||||
}
|
||||
|
||||
QualType InitialFromType = FromType;
|
||||
// Perform the first implicit conversion.
|
||||
switch (SCS.First) {
|
||||
case ICK_Identity:
|
||||
|
@ -3488,6 +3489,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
|
|
|
@ -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_literal_template() {
|
|||
}
|
||||
|
||||
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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue