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 Kind, + ASTContext &Ctx) const; + private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1279,6 +1279,23 @@ return getUnqualifiedType(); } +QualType QualType::setNullability(Optional 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> Type::getObjCSubstitutions( const DeclContext *dc) const { // Look through method scopes. 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/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: 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: 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 {};