ahatanak created this revision.
ahatanak added a reviewer: doug.gregor.
ahatanak added a subscriber: cfe-commits.

This patch fixes Sema to propagate the nullability of the initializer 
expression of a variable declared with auto or __auto_type to the deduced type. 
The patch consists of two parts:

- Define function QualType::setNullability, which is used to return a QualType 
with the specified nullability, and use it in computeConditionalNullability.
- Propagate nullability when type of auto is being deduced.

rdar://problem/27062504

https://reviews.llvm.org/D22794

Files:
  include/clang/AST/Type.h
  lib/AST/Type.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  test/Sema/nullability.c
  test/SemaCXX/nullability.cpp

Index: test/SemaCXX/nullability.cpp
===================================================================
--- test/SemaCXX/nullability.cpp
+++ test/SemaCXX/nullability.cpp
@@ -98,6 +98,11 @@
   TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}
 }
 
+void * _Nonnull DeduceAuto() {
+  auto *p = ReturnNullable();
+  return p; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
+}
+
 void ConditionalExpr(bool c) {
   struct Base {};
   struct Derived : Base {};
Index: test/Sema/nullability.c
===================================================================
--- test/Sema/nullability.c
+++ test/Sema/nullability.c
@@ -129,6 +129,13 @@
   accepts_nonnull_1(ptr); // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
 }
 
+int * _Nullable return_nullable();
+
+int * _Nonnull deduce_auto() {
+  __auto_type *p = return_nullable();
+  return p; // expected-warning{{implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull'}}
+}
+
 // Check nullability of conditional expressions.
 void conditional_expr(int c) {
   int * _Nonnull p;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7052,13 +7052,8 @@
   if (GetNullability(ResTy) == MergedKind)
     return ResTy;
 
-  // Strip all nullability from ResTy.
-  while (ResTy->getNullability(Ctx))
-    ResTy = ResTy.getSingleStepDesugaredType(Ctx);
-
-  // Create a new AttributedType with the new nullability kind.
-  auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind);
-  return Ctx.getAttributedType(NewAttr, ResTy, ResTy);
+  // Create a new type with the merged nullability kind.
+  return ResTy.setNullability(MergedKind, Ctx);
 }
 
 /// ActOnConditionalOp - Parse a ?: operation.  Note that 'LHS' may be null
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -9733,6 +9733,11 @@
       return;
     }
 
+    // Propagate init expression's nullability to the deduced type.
+    if (!Init->getType().isNull() && DeducedType->isAnyPointerType())
+      DeducedType = DeducedType.setNullability(
+          Init->getType()->getNullability(Context), Context);
+
     VDecl->setType(DeducedType);
     assert(VDecl->isLinkageValid());
 
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -1279,6 +1279,23 @@
   return getUnqualifiedType();
 }
 
+QualType QualType::setNullability(Optional<NullabilityKind> Kind,
+                                  ASTContext &Ctx) const {
+  assert(getTypePtr()->isAnyPointerType() && "type has to be a pointer type");
+  QualType ResTy = *this;
+
+  // Strip all nullability specifiers.
+  while (ResTy->getNullability(Ctx))
+    ResTy = ResTy.getSingleStepDesugaredType(Ctx);
+
+  if (!Kind)
+    return ResTy;
+
+  // Create a new AttributedType with the new nullability kind.
+  auto NewAttr = AttributedType::getNullabilityAttrKind(*Kind);
+  return Ctx.getAttributedType(NewAttr, ResTy, ResTy);
+}
+
 Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
                                const DeclContext *dc) const {
   // Look through method scopes.
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1093,6 +1093,10 @@
   /// Remove all qualifiers including _Atomic.
   QualType getAtomicUnqualifiedType() const;
 
+  /// Create a type having the specified nullability.
+  QualType setNullability(Optional<NullabilityKind> Kind,
+                          ASTContext &Ctx) const;
+
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to