From a57d91c2aede9cb8c5e43ab86cfaebe4e43f0161 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 25 Jul 2014 19:45:01 +0000 Subject: [PATCH] Objective-C. Warn if protocol used in an @protocol expression is a forward declaration as this results in undefined behavior. rdar://17768630 llvm-svn: 213968 --- clang/include/clang/Basic/DiagnosticGroups.td | 1 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaExpr.cpp | 9 +++++++++ clang/lib/Sema/SemaExprObjC.cpp | 2 ++ clang/test/SemaObjC/protocol-expr-1.m | 2 +- clang/test/SemaObjC/protocol-expr-neg-1.m | 19 +++++++++++++++++-- 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index b66cffe..deead56 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -428,6 +428,7 @@ def DeallocInCategory:DiagGroup<"dealloc-in-category">; def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">; def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>; def Protocol : DiagGroup<"protocol">; +def AtProtocol : DiagGroup<"at-protocol">; def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; def VariadicMacros : DiagGroup<"variadic-macros">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5499344..366f6d2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -566,6 +566,8 @@ def err_protocol_has_circular_dependency : Error< "protocol has circular dependency">; def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; +def warn_atprotocol_protocol : Warning< + "@protocol is using a forward protocol declaration of %0">, InGroup; def warn_readonly_property : Warning< "attribute 'readonly' of property %0 restricts attribute " "'readwrite' of property inherited from %1">; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 163973b..c2c886c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6756,6 +6756,15 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } + Expr *PRE = RHS.get()->IgnoreParenCasts(); + if (ObjCProtocolExpr *OPE = dyn_cast(PRE)) { + ObjCProtocolDecl *PDecl = OPE->getProtocol(); + if (PDecl && !PDecl->hasDefinition()) { + Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName(); + Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; + } + } + CastKind Kind = CK_Invalid; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 5002332..fb2c02b 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1105,6 +1105,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; } + if (PDecl->hasDefinition()) + PDecl = PDecl->getDefinition(); QualType Ty = Context.getObjCProtoType(); if (Ty.isNull()) diff --git a/clang/test/SemaObjC/protocol-expr-1.m b/clang/test/SemaObjC/protocol-expr-1.m index 94a0d9e..5ff3db4 100644 --- a/clang/test/SemaObjC/protocol-expr-1.m +++ b/clang/test/SemaObjC/protocol-expr-1.m @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // expected-no-diagnostics -@protocol fproto; +@protocol fproto @end @protocol p1 @end diff --git a/clang/test/SemaObjC/protocol-expr-neg-1.m b/clang/test/SemaObjC/protocol-expr-neg-1.m index 58ac8c0..aed56c0 100644 --- a/clang/test/SemaObjC/protocol-expr-neg-1.m +++ b/clang/test/SemaObjC/protocol-expr-neg-1.m @@ -2,7 +2,7 @@ @class Protocol; -@protocol fproto; +@protocol fproto; // expected-note {{'fproto' declared here}} @protocol p1 @end @@ -12,8 +12,23 @@ int main() { Protocol *proto = @protocol(p1); - Protocol *fproto = @protocol(fproto); + Protocol *fproto = @protocol(fproto); // expected-warning {{@protocol is using a forward protocol declaration of fproto}} Protocol *pp = @protocol(i); // expected-error {{cannot find protocol declaration for 'i'}} Protocol *p1p = @protocol(cl); // expected-error {{cannot find protocol declaration for 'cl'}} } +// rdar://17768630 +@protocol SuperProtocol; // expected-note {{'SuperProtocol' declared here}} +@protocol TestProtocol; // expected-note {{'TestProtocol' declared here}} + +@interface I +- (int) conformsToProtocol : (Protocol *)protocl; +@end + +int doesConform(id foo) { + return [foo conformsToProtocol:@protocol(TestProtocol)]; // expected-warning {{@protocol is using a forward protocol declaration of TestProtocol}} +} + +int doesConformSuper(id foo) { + return [foo conformsToProtocol:@protocol(SuperProtocol)]; // expected-warning {{@protocol is using a forward protocol declaration of SuperProtocol}} +} -- 2.7.4