ahatanak updated this revision to Diff 92583.
ahatanak added a comment.

Rebase and ping.


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_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,7 @@
+// 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'}}
+  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'}}
+}
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-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
@@ -7105,20 +7105,26 @@
 }
 
 /// 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, 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.
@@ -7220,7 +7226,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;
@@ -7235,8 +7240,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)
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10151,6 +10151,8 @@
     Init = Result.getAs<Expr>();
   }
 
+  checkVarDeclInit(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
@@ -2353,7 +2353,7 @@
 /// Checks if a the given expression evaluates to null.
 ///
 /// \brief Returns true if the value evaluates to null.
-static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
+static bool CheckNonNullExpr(const Sema &S, const Expr *Expr) {
   // If the expression has non-null type, it doesn't evaluate to null.
   if (auto nullability
         = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) {
@@ -2378,6 +2378,10 @@
           !Result);
 }
 
+bool Sema::checkNonNullExpr(const Expr *E) const {
+  return CheckNonNullExpr(*this, E);
+}
+
 static void CheckNonNullArgument(Sema &S,
                                  const Expr *ArgExpr,
                                  SourceLocation CallSiteLoc) {
@@ -7864,6 +7868,11 @@
   }
 }
 
+void Sema::checkVarDeclInit(QualType DeclTy, Expr *Init) {
+  if (isNonNullType(Context, DeclTy) && CheckNonNullExpr(*this, Init))
+    Diag(Init->getLocStart(), diag::warn_null_constant_to_nonnull) << DeclTy;
+}
+
 //===--- 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
@@ -10065,6 +10065,8 @@
 
   static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);
 
+  bool checkNonNullExpr(const Expr *E) const;
+
 private:
   bool CheckFormatArguments(const FormatAttr *Format,
                             ArrayRef<const Expr *> Args,
@@ -10100,6 +10102,8 @@
                           const AttrVec *Attrs = nullptr,
                           const FunctionDecl *FD = nullptr);
 
+  void checkVarDeclInit(QualType DeclTy, Expr *Init);
+
   void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
   void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
   void CheckBoolLikeConversion(Expr *E, SourceLocation CC);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -8919,6 +8919,10 @@
   "type %1">,
   InGroup<NullableToNonNullConversion>, 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
@@ -290,6 +290,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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D22391: [Sema] Add ... Akira Hatanaka via Phabricator via cfe-commits

Reply via email to