From a4b8abe065157e70975240c9e5d119f7e50c0b97 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Tue, 14 Jan 2020 19:51:08 -0800 Subject: [PATCH 1/2] [objc_direct] Allow for direct messages be sent to `self` when it is a Class Sending a message to `self` when it is const and within a class method is safe because we know that `self` is the Class itself. We can only relax this warning in ARC. Signed-off-by: Pierre Habouzit Radar-Id: rdar://problem/58581965 Differential Revision: https://reviews.llvm.org/D72747 (cherry picked from commit 7596d3c50c4b265612d326369e2a015cf8c60801) --- clang/lib/Sema/SemaExprObjC.cpp | 6 +++- clang/test/SemaObjC/method-direct-arc.m | 48 +++++++++++++++++++++++++ clang/test/SemaObjC/method-direct.m | 3 ++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaObjC/method-direct-arc.m diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 8d8e75103e999..de560350032dd 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -3010,7 +3010,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Method->getDeclName(); } - if (ReceiverType->isObjCClassType() && !isImplicit) { + // Under ARC, self can't be assigned, and doing a direct call to `self` + // when it's a Class is hence safe. For other cases, we can't trust `self` + // is what we think it is, so we reject it. + if (ReceiverType->isObjCClassType() && !isImplicit && + !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) { Diag(Receiver->getExprLoc(), diag::err_messaging_class_with_direct_method); Diag(Method->getLocation(), diag::note_direct_method_declared_at) diff --git a/clang/test/SemaObjC/method-direct-arc.m b/clang/test/SemaObjC/method-direct-arc.m new file mode 100644 index 0000000000000..6877cddb073b5 --- /dev/null +++ b/clang/test/SemaObjC/method-direct-arc.m @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -fobjc-arc -fsyntax-only -verify -Wselector-type-mismatch %s + +extern Class object_getClass(id); + +__attribute__((objc_root_class)) +@interface Root +- (Class)class; ++ (void)directMethod __attribute__((objc_direct)); // expected-note {{direct method 'directMethod' declared here}} ++ (void)anotherDirectMethod __attribute__((objc_direct)); +@end + +@implementation Root +- (Class)class +{ + return object_getClass(self); +} ++ (void)directMethod { +} ++ (void)anotherDirectMethod { + [self directMethod]; // this should not warn +} ++ (void)regularMethod { + [self directMethod]; // this should not warn + [self anotherDirectMethod]; // this should not warn +} +- (void)regularInstanceMethod { + [[self class] directMethod]; // expected-error {{messaging a Class with a method that is possibly direct}} +} +@end + +@interface Sub : Root +@end + +@implementation Sub ++ (void)foo { + [self directMethod]; // this should not warn +} +@end + +__attribute__((objc_root_class)) +@interface Other +@end + +@implementation Other ++ (void)bar { + [self directMethod]; // expected-error {{no known class method for selector 'directMethod'}} +} +@end diff --git a/clang/test/SemaObjC/method-direct.m b/clang/test/SemaObjC/method-direct.m index 4829a67cd8a9f..c2cbdbebdaf41 100644 --- a/clang/test/SemaObjC/method-direct.m +++ b/clang/test/SemaObjC/method-direct.m @@ -89,7 +89,10 @@ + (void)classRootDirect { } - (void)otherRootDirect { } ++ (void)someRootDirectMethod { // expected-note {{direct method 'someRootDirectMethod' declared here}} +} + (void)otherClassRootDirect { + [self someRootDirectMethod]; // expected-error {{messaging a Class with a method that is possibly direct}} } - (void)rootExtensionDirect { } From 67831e69fa81b4f9b46218a15d017a2702c9976e Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 22 Jan 2020 12:08:19 -0800 Subject: [PATCH 2/2] [objc_direct] do not add direct properties to the serialization array If we do, then the property_list_t length is wrong and class_getProperty gets very sad. Signed-off-by: Pierre Habouzit Radar-Id: rdar://problem/58804805 Differential Revision: https://reviews.llvm.org/D73219 (cherry picked from commit 52311d0483eecd60bdcc39dd3fb134f2412370f6) --- clang/lib/CodeGen/CGObjCMac.cpp | 6 ++++-- clang/test/CodeGenObjC/direct-properties.m | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenObjC/direct-properties.m diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index bda1fe99bf255..3b8c1bc57e2ec 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -3291,6 +3291,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, for (auto *PD : ClassExt->properties()) { if (IsClassProperty != PD->isClassProperty()) continue; + if (PD->isDirectProperty()) + continue; PropertySet.insert(PD->getIdentifier()); Properties.push_back(PD); } @@ -3302,6 +3304,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, // class extension. if (!PropertySet.insert(PD->getIdentifier()).second) continue; + if (PD->isDirectProperty()) + continue; Properties.push_back(PD); } @@ -3327,8 +3331,6 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, values.addInt(ObjCTypes.IntTy, Properties.size()); auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy); for (auto PD : Properties) { - if (PD->isDirectProperty()) - continue; auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy); property.add(GetPropertyName(PD->getIdentifier())); property.add(GetPropertyTypeString(PD, Container)); diff --git a/clang/test/CodeGenObjC/direct-properties.m b/clang/test/CodeGenObjC/direct-properties.m new file mode 100644 index 0000000000000..113ac12f18bfe --- /dev/null +++ b/clang/test/CodeGenObjC/direct-properties.m @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -o - | FileCheck %s + +__attribute__((objc_root_class)) +@interface A +@property(direct, readonly) int i; +@end + +__attribute__((objc_root_class)) +@interface B +@property(direct, readonly) int i; +@property(readonly) int j; +@end + +// CHECK-NOT: @"__OBJC_$_PROP_LIST_A" +@implementation A +@synthesize i = _i; +@end + +// CHECK: @"_OBJC_$_PROP_LIST_B" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1 +@implementation B +@synthesize i = _i; +@synthesize j = _j; +@end