Author: ahatanak Date: Fri Jul 27 21:06:13 2018 New Revision: 338189 URL: http://llvm.org/viewvc/llvm-project?rev=338189&view=rev Log: [Sema][ObjC] Warn when a method declared in a protocol takes a non-escaping parameter but the implementation's method takes an escaping parameter.
rdar://problem/39548196 Differential Revision: https://reviews.llvm.org/D49119 Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDeclObjC.cpp cfe/trunk/test/SemaObjCXX/noescape.mm Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=338189&r1=338188&r2=338189&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jul 27 21:06:13 2018 @@ -1733,6 +1733,8 @@ def warn_overriding_method_missing_noesc "__attribute__((noescape))">, InGroup<MissingNoEscape>; def note_overridden_marked_noescape : Note< "parameter of overridden method is annotated with __attribute__((noescape))">; +def note_cat_conform_to_noescape_prot : Note< + "%select{category|class extension}0 conforms to protocol %1 which defines method %2">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=338189&r1=338188&r2=338189&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Jul 27 21:06:13 2018 @@ -109,6 +109,30 @@ bool Sema::checkInitMethod(ObjCMethodDec return true; } +/// Issue a warning if the parameter of the overridden method is non-escaping +/// but the parameter of the overriding method is not. +static bool diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD, + Sema &S) { + if (OldD->hasAttr<NoEscapeAttr>() && !NewD->hasAttr<NoEscapeAttr>()) { + S.Diag(NewD->getLocation(), diag::warn_overriding_method_missing_noescape); + S.Diag(OldD->getLocation(), diag::note_overridden_marked_noescape); + return false; + } + + return true; +} + +/// Produce additional diagnostics if a category conforms to a protocol that +/// defines a method taking a non-escaping parameter. +static void diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD, + const ObjCCategoryDecl *CD, + const ObjCProtocolDecl *PD, Sema &S) { + if (!diagnoseNoescape(NewD, OldD, S)) + S.Diag(CD->getLocation(), diag::note_cat_conform_to_noescape_prot) + << CD->IsClassExtension() << PD + << cast<ObjCMethodDecl>(NewD->getDeclContext()); +} + void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden) { if (Overridden->hasRelatedResultType() && @@ -192,13 +216,7 @@ void Sema::CheckObjCMethodOverride(ObjCM Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter"; } - // A parameter of the overriding method should be annotated with noescape - // if the corresponding parameter of the overridden method is annotated. - if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) { - Diag(newDecl->getLocation(), - diag::warn_overriding_method_missing_noescape); - Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape); - } + diagnoseNoescape(newDecl, oldDecl, *this); } } @@ -4643,6 +4661,22 @@ Decl *Sema::ActOnMethodDeclaration( << ObjCMethod->getDeclName(); } } + + // Warn if a method declared in a protocol to which a category or + // extension conforms is non-escaping and the implementation's method is + // escaping. + for (auto *C : IDecl->visible_categories()) + for (auto &P : C->protocols()) + if (auto *IMD = P->lookupMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) { + assert(ObjCMethod->parameters().size() == + IMD->parameters().size() && + "Methods have different number of parameters"); + auto OI = IMD->param_begin(), OE = IMD->param_end(); + auto NI = ObjCMethod->param_begin(); + for (; OI != OE; ++OI, ++NI) + diagnoseNoescape(*NI, *OI, C, P, *this); + } } } else { cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); Modified: cfe/trunk/test/SemaObjCXX/noescape.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/noescape.mm?rev=338189&r1=338188&r2=338189&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/noescape.mm (original) +++ cfe/trunk/test/SemaObjCXX/noescape.mm Fri Jul 27 21:06:13 2018 @@ -88,3 +88,42 @@ void test0() { S5<&noescapeFunc2> ne1; } + +@protocol NoescapeProt +-(void) m0:(int*)__attribute__((noescape)) p; // expected-note 2 {{parameter of overridden method is annotated with __attribute__((noescape))}} ++(void) m1:(int*)__attribute__((noescape)) p; +-(void) m1:(int*) p; +@end + +__attribute__((objc_root_class)) +@interface C3 +-(void) m0:(int*) p; ++(void) m1:(int*)__attribute__((noescape)) p; +-(void) m1:(int*) p; +@end + +@interface C3 () <NoescapeProt> // expected-note {{class extension conforms to protocol 'NoescapeProt' which defines method 'm0:'}} +@end + +@implementation C3 +-(void) m0:(int*) p { // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}} +} ++(void) m1:(int*)__attribute__((noescape)) p { +} +-(void) m1:(int*) p { +} +@end + +__attribute__((objc_root_class)) +@interface C4 <NoescapeProt> +-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}} +@end + +@implementation C4 +-(void) m0:(int*) p { +} ++(void) m1:(int*)__attribute__((noescape)) p { +} +-(void) m1:(int*) p { +} +@end _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits