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,26 +156,39 @@ return false; } -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(); +static inline bool isNSStringInterface(ASTContext &Ctx, ObjCInterfaceDecl *Cls, bool AllowNSAttributedString = false) { if (!Cls) return false; - IdentifierInfo* ClsName = Cls->getIdentifier(); + IdentifierInfo *ClsName = Cls->getIdentifier(); - if (AllowNSAttributedString && - ClsName == &Ctx.Idents.get("NSAttributedString")) - return true; + 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; + + 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; + + auto *OMD = dyn_cast(D); + if (!OMD) + return false; + + return isNSStringInterface(Ctx, OMD->getClassInterface(), AllowNSAttributedString); +} + static inline bool isCFStringType(QualType T, ASTContext &Ctx) { const auto *PT = T->getAs(); if (!PT) @@ -3390,6 +3403,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)));