ahatanak updated this revision to Diff 150218.
ahatanak marked an inline comment as done.
ahatanak added a reviewer: dcoughlin.
ahatanak set the repository for this revision to rC Clang.
ahatanak added a comment.
Sorry for the delay in responding. I've addressed Jordan's review comments.
I had to make changes to a couple of tests in Analysis. In particular, I'm not
sure whether we should try to avoid producing extra diagnostics in
test/Analysis/nullability_nullonly.mm or whether it's possible to do so in Sema.
Repository:
rC Clang
https://reviews.llvm.org/D22391
Files:
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
test/Analysis/nullability-no-arc.mm
test/Analysis/nullability.mm
test/Analysis/nullability_nullonly.mm
test/Sema/conditional-expr.c
test/Sema/null_constant_to_nonnull.c
Index: test/Sema/null_constant_to_nonnull.c
===================================================================
--- /dev/null
+++ test/Sema/null_constant_to_nonnull.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify
+
+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'}}
+ p0 = 0; // expected-warning{{implicitly casting a null constant to non-nullable pointer type 'int * _Nonnull'}}
+ p0 = (int * _Nonnull)0; // explicit cast silences warnings
+ int * _Nonnull p1;
+ int * _Nonnull p2 = c ? p1 : 0; // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
+ p2 = c ? p1 : (int * _Nonnull)0; // explicit cast silences warnings
+}
Index: test/Sema/conditional-expr.c
===================================================================
--- test/Sema/conditional-expr.c
+++ test/Sema/conditional-expr.c
@@ -17,7 +17,7 @@
dp = ip; // expected-warning {{incompatible pointer types assigning to 'double *' from 'int *'}}
dp = 0 ? (double *)0 : (void *)0;
vp = 0 ? (double *)0 : (void *)0;
- ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning to 'int *' from 'double *'}}
+ ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning to 'int *' from 'double * _Nullable'}}
const int *cip;
vp = (0 ? vp : cip); // expected-warning {{discards qualifiers}}
@@ -90,7 +90,7 @@
int f0(int a) {
// GCC considers this a warning.
- return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'int'}}
+ return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void * _Nullable' from a function with result type 'int'}}
}
int f2(int x) {
Index: test/Analysis/nullability_nullonly.mm
===================================================================
--- test/Analysis/nullability_nullonly.mm
+++ test/Analysis/nullability_nullonly.mm
@@ -100,7 +100,7 @@
}
void testObjCARCExplicitZeroInitialization() {
- TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{nil assigned to a pointer which is expected to have non-null value}}
+ TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{nil assigned to a pointer which is expected to have non-null value}} expected-warning{{implicitly casting a null constant to non-nullable pointer type 'TestObject * _Nonnull __strong'}}
}
// Under ARC, returned expressions of ObjC objects types are are implicitly
Index: test/Analysis/nullability.mm
===================================================================
--- test/Analysis/nullability.mm
+++ test/Analysis/nullability.mm
@@ -180,7 +180,7 @@
// Since we've already had an invariant violation along this path,
// we shouldn't warn here.
- nonnullLocalWithAssignmentInInitializer = 0;
+ nonnullLocalWithAssignmentInInitializer = 0; // expected-warning {{implicitly casting a null constant to non-nullable pointer type}}
(void)nonnullLocalWithAssignmentInInitializer;
}
@@ -192,7 +192,7 @@
// Since we've already had an invariant violation along this path,
// we shouldn't warn here.
- nonnullLocalWithAssignment = 0;
+ nonnullLocalWithAssignment = 0; // expected-warning {{implicitly casting a null constant to non-nullable pointer type}}
(void)nonnullLocalWithAssignment;
}
Index: test/Analysis/nullability-no-arc.mm
===================================================================
--- test/Analysis/nullability-no-arc.mm
+++ test/Analysis/nullability-no-arc.mm
@@ -43,7 +43,7 @@
}
void testObjCNonARCExplicitZeroInitialization() {
- TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{nil assigned to a pointer which is expected to have non-null value}}
+ TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{nil assigned to a pointer which is expected to have non-null value}} expected-warning {{implicitly casting a null constant to non-nullable pointer type 'TestObject * _Nonnull'}}
}
@interface ClassWithInitializers : NSObject
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7157,20 +7157,27 @@
}
/// Compute the nullability of a conditional expression.
-static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
- QualType LHSTy, QualType RHSTy,
- ASTContext &Ctx) {
+static QualType computeConditionalNullability(Sema &S, QualType ResTy,
+ bool IsBin, Expr *LHSExpr,
+ Expr *RHSExpr, ASTContext &Ctx) {
if (!ResTy->isAnyPointerType())
return ResTy;
- auto GetNullability = [&Ctx](QualType Ty) {
+ auto GetNullability = [&S, &Ctx](QualType Ty, Expr *E = nullptr) {
+ // If E evaluates to a null constant and doesn't have a non-null type,
+ // return nullable.
+ if (E && S.CheckNonNullExpr(E))
+ return NullabilityKind::Nullable;
+
Optional<NullabilityKind> Kind = Ty->getNullability(Ctx);
if (Kind)
return *Kind;
return NullabilityKind::Unspecified;
};
- auto LHSKind = GetNullability(LHSTy), RHSKind = GetNullability(RHSTy);
+ QualType LHSTy = LHSExpr->getType(), RHSTy = RHSExpr->getType();
+ auto LHSKind = GetNullability(LHSTy, LHSExpr);
+ auto RHSKind = GetNullability(RHSTy, RHSExpr);
NullabilityKind MergedKind;
// Compute nullability of a binary conditional expression.
@@ -7282,7 +7289,6 @@
LHSExpr = CondExpr = opaqueValue;
}
- QualType LHSTy = LHSExpr->getType(), RHSTy = RHSExpr->getType();
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
ExprResult Cond = CondExpr, LHS = LHSExpr, RHS = RHSExpr;
@@ -7297,8 +7303,8 @@
CheckBoolLikeConversion(Cond.get(), QuestionLoc);
- result = computeConditionalNullability(result, commonExpr, LHSTy, RHSTy,
- Context);
+ result = computeConditionalNullability(*this, result, commonExpr, LHSExpr,
+ RHSExpr, Context);
if (!commonExpr)
return new (Context)
@@ -11094,6 +11100,9 @@
CheckForNullPointerDereference(*this, LHSExpr);
+ if (const auto *DeclRef = dyn_cast<DeclRefExpr>(LHSExpr))
+ checkNullConstantToNonNull(DeclRef->getType(), RHS.get());
+
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10771,6 +10771,8 @@
Init = Result.getAs<Expr>();
}
+ checkNullConstantToNonNull(DclT, Init);
+
// Check for self-references within variable initializers.
// Variables declared within a function/method body (except for references)
// are handled by a dataflow analysis.
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -2771,10 +2771,10 @@
/// Checks if a the given expression evaluates to null.
///
/// Returns true if the value evaluates to null.
-static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
+bool Sema::CheckNonNullExpr(const Expr *Expr) const {
// If the expression has non-null type, it doesn't evaluate to null.
if (auto nullability
- = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) {
+ = Expr->IgnoreImplicit()->getType()->getNullability(Context)) {
if (*nullability == NullabilityKind::NonNull)
return false;
}
@@ -2792,14 +2792,14 @@
bool Result;
return (!Expr->isValueDependent() &&
- Expr->EvaluateAsBooleanCondition(Result, S.Context) &&
+ Expr->EvaluateAsBooleanCondition(Result, Context) &&
!Result);
}
static void CheckNonNullArgument(Sema &S,
const Expr *ArgExpr,
SourceLocation CallSiteLoc) {
- if (CheckNonNullExpr(S, ArgExpr))
+ if (S.CheckNonNullExpr(ArgExpr))
S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr,
S.PDiag(diag::warn_null_arg) << ArgExpr->getSourceRange());
}
@@ -8543,7 +8543,7 @@
// Check if the return value is null but should not be.
if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
(!isObjCMethod && isNonNullType(Context, lhsType))) &&
- CheckNonNullExpr(*this, RetValExp))
+ CheckNonNullExpr(RetValExp))
Diag(ReturnLoc, diag::warn_null_ret)
<< (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
@@ -8558,13 +8558,18 @@
const FunctionProtoType *Proto
= FD->getType()->castAs<FunctionProtoType>();
if (!Proto->isNothrow(/*ResultIfDependent*/true) &&
- CheckNonNullExpr(*this, RetValExp))
+ CheckNonNullExpr(RetValExp))
Diag(ReturnLoc, diag::warn_operator_new_returns_null)
<< FD << getLangOpts().CPlusPlus11;
}
}
}
+void Sema::checkNullConstantToNonNull(QualType DstTy, Expr *RHSExpr) {
+ if (isNonNullType(Context, DstTy) && CheckNonNullExpr(RHSExpr))
+ Diag(RHSExpr->getLocStart(), diag::warn_null_constant_to_nonnull) << DstTy;
+}
+
//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===//
/// Check for comparisons of floating point operands using != and ==.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -10444,6 +10444,10 @@
static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);
+ /// Returns true if the expression evaluates to null and doesn't have a
+ /// non-null type.
+ bool CheckNonNullExpr(const Expr *E) const;
+
private:
bool CheckFormatArguments(const FormatAttr *Format,
ArrayRef<const Expr *> Args,
@@ -10479,6 +10483,9 @@
const AttrVec *Attrs = nullptr,
const FunctionDecl *FD = nullptr);
+ /// Check null constant to nonnull conversion.
+ void checkNullConstantToNonNull(QualType DstTy, Expr *RHSExpr);
+
public:
void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -9135,6 +9135,10 @@
"zero as null pointer constant">,
InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
+def warn_null_constant_to_nonnull : Warning<
+ "implicitly casting a null constant to non-nullable pointer type %0">,
+ InGroup<NullConstantToNonnull>;
+
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/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -337,6 +337,7 @@
def NullabilityDeclSpec : DiagGroup<"nullability-declspec">;
def NullabilityInferredOnNestedType : DiagGroup<"nullability-inferred-on-nested-type">;
def NullableToNonNullConversion : DiagGroup<"nullable-to-nonnull-conversion">;
+def NullConstantToNonnull : DiagGroup<"null-constant-to-nonnull">;
def NullabilityCompletenessOnArrays : DiagGroup<"nullability-completeness-on-arrays">;
def NullabilityCompleteness : DiagGroup<"nullability-completeness",
[NullabilityCompletenessOnArrays]>;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits