diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -156,24 +156,42 @@ return false; } +static inline bool isNSStringInterface(ASTContext &Ctx, ObjCInterfaceDecl *Cls, + bool AllowNSAttributedString = false) { + if (!Cls) + return false; + + IdentifierInfo *ClsName = Cls->getIdentifier(); + + if (ClsName == &Ctx.Idents.get("NSAttributedString")) + return AllowNSAttributedString; + // FIXME: Should we walk the chain of classes? + return ClsName == &Ctx.Idents.get("NSString") || + ClsName == &Ctx.Idents.get("NSMutableString"); +} + static inline bool isNSStringType(QualType T, ASTContext &Ctx, bool AllowNSAttributedString = false) { const auto *PT = T->getAs(); if (!PT) return false; - ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); - if (!Cls) + return isNSStringInterface(Ctx, PT->getObjectType()->getInterface(), + AllowNSAttributedString); +} + +static inline bool +isInstancetypeNSStringType(ASTContext &Ctx, QualType T, Decl *D, + bool AllowNSAttributedString = false) { + if (T.getTypePtr() != Ctx.getObjCInstanceTypeDecl()->getTypeForDecl()) return false; - IdentifierInfo* ClsName = Cls->getIdentifier(); + auto *OMD = dyn_cast(D); + if (!OMD) + return false; - if (AllowNSAttributedString && - ClsName == &Ctx.Idents.get("NSAttributedString")) - return true; - // FIXME: Should we walk the chain of classes? - return ClsName == &Ctx.Idents.get("NSString") || - ClsName == &Ctx.Idents.get("NSMutableString"); + return isNSStringInterface(Ctx, OMD->getClassInterface(), + AllowNSAttributedString); } static inline bool isCFStringType(QualType T, ASTContext &Ctx) { @@ -3390,6 +3408,7 @@ Ty = getFunctionOrMethodResultType(D); if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) && !isCFStringType(Ty, S.Context) && + !isInstancetypeNSStringType(S.Context, Ty, D) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) diff --git a/clang/test/SemaObjC/format-arg-attribute.m b/clang/test/SemaObjC/format-arg-attribute.m --- a/clang/test/SemaObjC/format-arg-attribute.m +++ b/clang/test/SemaObjC/format-arg-attribute.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -@class NSString; +@interface NSString ++(instancetype)stringWithCString:(const char *)cstr __attribute__((format_arg(1))); +@end + @class NSAttributedString; extern NSString *fa2 (const NSString *) __attribute__((format_arg(1)));