Skip to content

Commit a6b5e00

Browse files
committedJul 28, 2018
[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 llvm-svn: 338189
1 parent a4005e1 commit a6b5e00

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed
 

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,8 @@ def warn_overriding_method_missing_noescape : Warning<
17331733
"__attribute__((noescape))">, InGroup<MissingNoEscape>;
17341734
def note_overridden_marked_noescape : Note<
17351735
"parameter of overridden method is annotated with __attribute__((noescape))">;
1736+
def note_cat_conform_to_noescape_prot : Note<
1737+
"%select{category|class extension}0 conforms to protocol %1 which defines method %2">;
17361738

17371739
def err_covariant_return_inaccessible_base : Error<
17381740
"invalid covariant return for virtual function: %1 is a "

‎clang/lib/Sema/SemaDeclObjC.cpp

+41-7
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,30 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
109109
return true;
110110
}
111111

112+
/// Issue a warning if the parameter of the overridden method is non-escaping
113+
/// but the parameter of the overriding method is not.
114+
static bool diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
115+
Sema &S) {
116+
if (OldD->hasAttr<NoEscapeAttr>() && !NewD->hasAttr<NoEscapeAttr>()) {
117+
S.Diag(NewD->getLocation(), diag::warn_overriding_method_missing_noescape);
118+
S.Diag(OldD->getLocation(), diag::note_overridden_marked_noescape);
119+
return false;
120+
}
121+
122+
return true;
123+
}
124+
125+
/// Produce additional diagnostics if a category conforms to a protocol that
126+
/// defines a method taking a non-escaping parameter.
127+
static void diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
128+
const ObjCCategoryDecl *CD,
129+
const ObjCProtocolDecl *PD, Sema &S) {
130+
if (!diagnoseNoescape(NewD, OldD, S))
131+
S.Diag(CD->getLocation(), diag::note_cat_conform_to_noescape_prot)
132+
<< CD->IsClassExtension() << PD
133+
<< cast<ObjCMethodDecl>(NewD->getDeclContext());
134+
}
135+
112136
void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
113137
const ObjCMethodDecl *Overridden) {
114138
if (Overridden->hasRelatedResultType() &&
@@ -192,13 +216,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
192216
Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
193217
}
194218

195-
// A parameter of the overriding method should be annotated with noescape
196-
// if the corresponding parameter of the overridden method is annotated.
197-
if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) {
198-
Diag(newDecl->getLocation(),
199-
diag::warn_overriding_method_missing_noescape);
200-
Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
201-
}
219+
diagnoseNoescape(newDecl, oldDecl, *this);
202220
}
203221
}
204222

@@ -4643,6 +4661,22 @@ Decl *Sema::ActOnMethodDeclaration(
46434661
<< ObjCMethod->getDeclName();
46444662
}
46454663
}
4664+
4665+
// Warn if a method declared in a protocol to which a category or
4666+
// extension conforms is non-escaping and the implementation's method is
4667+
// escaping.
4668+
for (auto *C : IDecl->visible_categories())
4669+
for (auto &P : C->protocols())
4670+
if (auto *IMD = P->lookupMethod(ObjCMethod->getSelector(),
4671+
ObjCMethod->isInstanceMethod())) {
4672+
assert(ObjCMethod->parameters().size() ==
4673+
IMD->parameters().size() &&
4674+
"Methods have different number of parameters");
4675+
auto OI = IMD->param_begin(), OE = IMD->param_end();
4676+
auto NI = ObjCMethod->param_begin();
4677+
for (; OI != OE; ++OI, ++NI)
4678+
diagnoseNoescape(*NI, *OI, C, P, *this);
4679+
}
46464680
}
46474681
} else {
46484682
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);

‎clang/test/SemaObjCXX/noescape.mm

+39
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,42 @@ void test0() {
8888

8989
S5<&noescapeFunc2> ne1;
9090
}
91+
92+
@protocol NoescapeProt
93+
-(void) m0:(int*)__attribute__((noescape)) p; // expected-note 2 {{parameter of overridden method is annotated with __attribute__((noescape))}}
94+
+(void) m1:(int*)__attribute__((noescape)) p;
95+
-(void) m1:(int*) p;
96+
@end
97+
98+
__attribute__((objc_root_class))
99+
@interface C3
100+
-(void) m0:(int*) p;
101+
+(void) m1:(int*)__attribute__((noescape)) p;
102+
-(void) m1:(int*) p;
103+
@end
104+
105+
@interface C3 () <NoescapeProt> // expected-note {{class extension conforms to protocol 'NoescapeProt' which defines method 'm0:'}}
106+
@end
107+
108+
@implementation C3
109+
-(void) m0:(int*) p { // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
110+
}
111+
+(void) m1:(int*)__attribute__((noescape)) p {
112+
}
113+
-(void) m1:(int*) p {
114+
}
115+
@end
116+
117+
__attribute__((objc_root_class))
118+
@interface C4 <NoescapeProt>
119+
-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
120+
@end
121+
122+
@implementation C4
123+
-(void) m0:(int*) p {
124+
}
125+
+(void) m1:(int*)__attribute__((noescape)) p {
126+
}
127+
-(void) m1:(int*) p {
128+
}
129+
@end

0 commit comments

Comments
 (0)
Please sign in to comment.