Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -2263,19 +2263,15 @@ /// Represents a pointer type decayed from an array or function type. class DecayedType : public AdjustedType { - DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) - : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { - assert(isa(getAdjustedType())); - } + inline + DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); friend class ASTContext; // ASTContext creates these. public: QualType getDecayedType() const { return getAdjustedType(); } - QualType getPointeeType() const { - return cast(getDecayedType())->getPointeeType(); - } + inline QualType getPointeeType() const; static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } }; @@ -5947,6 +5943,23 @@ return cast(getUnqualifiedDesugaredType()); } +DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, + QualType CanonicalPtr) + : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { +#ifndef NDEBUG + QualType Adjusted = getAdjustedType(); + (void)AttributedType::stripOuterNullability(Adjusted); + assert(isa(Adjusted)); +#endif +} + +QualType DecayedType::getPointeeType() const { + QualType Decayed = getDecayedType(); + (void)AttributedType::stripOuterNullability(Decayed); + return cast(Decayed)->getPointeeType(); +} + + } // end namespace clang #endif Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3097,6 +3097,9 @@ /// method) or an Objective-C property attribute, rather than as an /// underscored type specifier. /// + /// \param isPrototypeContext Whether we're in a function-like context where + /// an array type will decay to a pointer. + /// /// \param overrideExisting Whether to override an existing, locally-specified /// nullability specifier rather than complaining about the conflict. /// @@ -3104,6 +3107,7 @@ bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, SourceLocation nullabilityLoc, bool isContextSensitive, + bool isPrototypeContext, bool implicit, bool overrideExisting = false); Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -4771,7 +4771,15 @@ QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); // int x[restrict 4] -> int *restrict - return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); + QualType Result = getQualifiedType(PtrTy, + PrettyArrayType->getIndexTypeQualifiers()); + + // int x[_Nullable] -> int * _Nullable + if (auto Nullability = Ty->getNullability(*this)) { + Result = const_cast(this)->getAttributedType( + AttributedType::getNullabilityAttrKind(*Nullability), Result, Result); + } + return Result; } QualType ASTContext::getBaseElementType(const ArrayType *array) const { Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2491,10 +2491,12 @@ case Type::Pointer: return CreateType(cast(Ty), Unit); case Type::Adjusted: - case Type::Decayed: + case Type::Decayed: { // Decayed and adjusted types use the adjusted type in LLVM and DWARF. - return CreateType( - cast(cast(Ty)->getAdjustedType()), Unit); + QualType Adjusted = cast(Ty)->getAdjustedType(); + (void)AttributedType::stripOuterNullability(Adjusted); + return CreateType(cast(Adjusted), Unit); + } case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -6275,8 +6275,7 @@ T.consumeClose(); - ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(DS.getAttributes()); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), @@ -6284,7 +6283,7 @@ NumElements.get(), T.getOpenLocation(), T.getCloseLocation()), - attrs, T.getCloseLocation()); + DS.getAttributes(), T.getCloseLocation()); } /// Diagnose brackets before an identifier. Index: lib/Sema/SemaAPINotes.cpp =================================================================== --- lib/Sema/SemaAPINotes.cpp +++ lib/Sema/SemaAPINotes.cpp @@ -46,16 +46,21 @@ } QualType type; + bool isPrototypeContext; // Nullability for a function/method appertains to the retain type. if (auto function = dyn_cast(decl)) { type = function->getReturnType(); + isPrototypeContext = true; } else if (auto method = dyn_cast(decl)) { type = method->getReturnType(); + isPrototypeContext = true; } else if (auto value = dyn_cast(decl)) { type = value->getType(); + isPrototypeContext = isa(value); } else if (auto property = dyn_cast(decl)) { type = property->getType(); + isPrototypeContext = false; } else { return; } @@ -64,7 +69,7 @@ QualType origType = type; S.checkNullabilityTypeSpecifier(type, nullability, decl->getLocation(), /*isContextSensitive=*/false, - /*implicit=*/true, + isPrototypeContext, /*implicit=*/true, overrideExisting); if (type.getTypePtr() == origType.getTypePtr()) return; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5808,6 +5808,7 @@ NullabilityKind nullability, SourceLocation nullabilityLoc, bool isContextSensitive, + bool isPrototypeContext, bool implicit, bool overrideExisting) { if (!implicit) { @@ -5889,7 +5890,8 @@ } // If this definitely isn't a pointer type, reject the specifier. - if (!desugared->canHaveNullability()) { + if (!desugared->canHaveNullability() && + !(isPrototypeContext && desugared->isArrayType())) { if (!implicit) { Diag(nullabilityLoc, diag::err_nullability_nonpointer) << DiagNullabilityKind(nullability, isContextSensitive) << type; @@ -6647,12 +6649,14 @@ // don't want to distribute the nullability specifier past any // dependent type, because that complicates the user model. if (type->canHaveNullability() || type->isDependentType() || + type->isArrayType() || !distributeNullabilityTypeAttr(state, type, attr)) { if (state.getSema().checkNullabilityTypeSpecifier( type, mapNullabilityAttrKind(attr.getKind()), attr.getLoc(), attr.isContextSensitiveKeywordAttribute(), + state.getDeclarator().isPrototypeContext(), /*implicit=*/false)) { attr.setInvalid(); }