Skip to content

Commit d976623

Browse files
authored
Merge pull request #328 from MadCoder/eng/PR-2684889-direct
Implement __attribute__((objc_direct)), __attribute__((objc_direct_me…
2 parents 22922bd + 11d47b3 commit d976623

24 files changed

+1024
-50
lines changed

clang/include/clang/AST/DeclObjC.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
410410
/// \return the type for \c self and set \arg selfIsPseudoStrong and
411411
/// \arg selfIsConsumed accordingly.
412412
QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID,
413-
bool &selfIsPseudoStrong, bool &selfIsConsumed);
413+
bool &selfIsPseudoStrong, bool &selfIsConsumed) const;
414414

415415
ImplicitParamDecl * getSelfDecl() const { return SelfDecl; }
416416
void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; }
@@ -476,6 +476,9 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
476476
ObjCMethodDeclBits.HasSkippedBody = Skipped;
477477
}
478478

479+
/// True if the method is tagged as objc_direct
480+
bool isDirectMethod() const;
481+
479482
/// Returns the property associated with this method's selector.
480483
///
481484
/// Note that even if this particular method is not marked as a property
@@ -757,13 +760,14 @@ class ObjCPropertyDecl : public NamedDecl {
757760
/// property attribute rather than a type qualifier.
758761
OBJC_PR_nullability = 0x1000,
759762
OBJC_PR_null_resettable = 0x2000,
760-
OBJC_PR_class = 0x4000
763+
OBJC_PR_class = 0x4000,
764+
OBJC_PR_direct = 0x8000
761765
// Adding a property should change NumPropertyAttrsBits
762766
};
763767

764768
enum {
765769
/// Number of bits fitting all the property attributes.
766-
NumPropertyAttrsBits = 15
770+
NumPropertyAttrsBits = 16
767771
};
768772

769773
enum SetterKind { Assign, Retain, Copy, Weak };
@@ -886,6 +890,7 @@ class ObjCPropertyDecl : public NamedDecl {
886890

887891
bool isInstanceProperty() const { return !isClassProperty(); }
888892
bool isClassProperty() const { return PropertyAttributes & OBJC_PR_class; }
893+
bool isDirectProperty() const { return PropertyAttributes & OBJC_PR_direct; }
889894

890895
ObjCPropertyQueryKind getQueryKind() const {
891896
return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :

clang/include/clang/Basic/Attr.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,20 @@ def ObjCDesignatedInitializer : Attr {
18711871
let Documentation = [Undocumented];
18721872
}
18731873

1874+
def ObjCDirect : Attr {
1875+
let Spellings = [Clang<"objc_direct">];
1876+
let Subjects = SubjectList<[ObjCMethod], ErrorDiag>;
1877+
let LangOpts = [ObjC];
1878+
let Documentation = [ObjCDirectDocs];
1879+
}
1880+
1881+
def ObjCDirectMembers : Attr {
1882+
let Spellings = [Clang<"objc_direct_members">];
1883+
let Subjects = SubjectList<[ObjCImpl, ObjCCategory], ErrorDiag>;
1884+
let LangOpts = [ObjC];
1885+
let Documentation = [ObjCDirectMembersDocs];
1886+
}
1887+
18741888
def ObjCRuntimeName : Attr {
18751889
let Spellings = [Clang<"objc_runtime_name">];
18761890
let Subjects = SubjectList<[ObjCInterface, ObjCProtocol], ErrorDiag>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,6 +4122,104 @@ overheads associated with defining and calling such a method.
41224122
}];
41234123
}
41244124

4125+
def ObjCDirectDocs : Documentation {
4126+
let Category = DocCatDecl;
4127+
let Content = [{
4128+
The ``objc_direct`` attribute can be used to mark an Objective-C method as
4129+
being *direct*. A direct method is treated statically like an ordinary method,
4130+
but dynamically it behaves more like a C function. This lowers some of the costs
4131+
associated with the method but also sacrifices some of the ordinary capabilities
4132+
of Objective-C methods.
4133+
4134+
A message send of a direct method calls the implementation directly, as if it
4135+
were a C function, rather than using ordinary Objective-C method dispatch. This
4136+
is substantially faster and potentially allows the implementation to be inlined,
4137+
but it also means the method cannot be overridden in subclasses or replaced
4138+
dynamically, as ordinary Objective-C methods can.
4139+
4140+
Furthermore, a direct method is not listed in the class's method lists. This
4141+
substantially reduces the code-size overhead of the method but also means it
4142+
cannot be called dynamically using ordinary Objective-C method dispatch at all;
4143+
in particular, this means that it cannot override a superclass method or satisfy
4144+
a protocol requirement.
4145+
4146+
Because a direct method cannot be overridden, it is an error to perform
4147+
a ``super`` message send of one.
4148+
4149+
Although a message send of a direct method causes the method to be called
4150+
directly as if it were a C function, it still obeys Objective-C semantics in other
4151+
ways:
4152+
4153+
- If the receiver is ``nil``, the message send does nothing and returns the zero value
4154+
for the return type.
4155+
4156+
- A message send of a direct class method will cause the class to be initialized,
4157+
including calling the ``+initialize`` method if present.
4158+
4159+
- The implicit ``_cmd`` parameter containing the method's selector is still defined.
4160+
In order to minimize code-size costs, the implementation will not emit a reference
4161+
to the selector if the parameter is unused within the method.
4162+
4163+
Symbols for direct method implementations are implicitly given hidden
4164+
visibility, meaning that they can only be called within the same linkage unit.
4165+
4166+
It is an error to do any of the following:
4167+
4168+
- declare a direct method in a protocol,
4169+
- declare an override of a direct method with a method in a subclass,
4170+
- declare an override of a non-direct method with a direct method in a subclass,
4171+
- declare a method with different directness in different class interfaces, or
4172+
- implement a non-direct method (as declared in any class interface) with a direct method.
4173+
4174+
If any of these rules would be violated if every method defined in an
4175+
``@implementation`` within a single linkage unit were declared in an
4176+
appropriate class interface, the program is ill-formed with no diagnostic
4177+
required. If a violation of this rule is not diagnosed, behavior remains
4178+
well-defined; this paragraph is simply reserving the right to diagnose such
4179+
conflicts in the future, not to treat them as undefined behavior.
4180+
4181+
Additionally, Clang will warn about any ``@selector`` expression that
4182+
names a selector that is only known to be used for direct methods.
4183+
4184+
For the purpose of these rules, a "class interface" includes a class's primary
4185+
``@interface`` block, its class extensions, its categories, its declared protocols,
4186+
and all the class interfaces of its superclasses.
4187+
4188+
An Objective-C property can be declared with the ``direct`` property
4189+
attribute. If a direct property declaration causes an implicit declaration of
4190+
a getter or setter method (that is, if the given method is not explicitly
4191+
declared elsewhere), the method is declared to be direct.
4192+
4193+
Some programmers may wish to make many methods direct at once. In order
4194+
to simplify this, the ``objc_direct_members`` attribute is provided; see its
4195+
documentation for more information.
4196+
}];
4197+
}
4198+
4199+
def ObjCDirectMembersDocs : Documentation {
4200+
let Category = DocCatDecl;
4201+
let Content = [{
4202+
The ``objc_direct_members`` attribute can be placed on an Objective-C
4203+
``@interface`` or ``@implementation`` to mark that methods declared
4204+
therein should be considered direct by default. See the documentation
4205+
for ``objc_direct`` for more information about direct methods.
4206+
4207+
When ``objc_direct_members`` is placed on an ``@interface`` block, every
4208+
method in the block is considered to be declared as direct. This includes any
4209+
implicit method declarations introduced by property declarations. If the method
4210+
redeclares a non-direct method, the declaration is ill-formed, exactly as if the
4211+
method was annotated with the ``objc_direct`` attribute. ``objc_direct_members``
4212+
cannot be placed on the primary interface of a class, only on category or class
4213+
extension interfaces.
4214+
4215+
When ``objc_direct_members`` is placed on an ``@implementation`` block,
4216+
methods defined in the block are considered to be declared as direct unless
4217+
they have been previously declared as non-direct in any interface of the class.
4218+
This includes the implicit method definitions introduced by synthesized
4219+
properties, including auto-synthesized properties.
4220+
}];
4221+
}
4222+
41254223
def SelectAnyDocs : Documentation {
41264224
let Category = DocCatDecl;
41274225
let Content = [{

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,22 @@ def warn_objc_boxing_invalid_utf8_string : Warning<
10371037
"string is ill-formed as UTF-8 and will become a null %0 when boxed">,
10381038
InGroup<ObjCBoxing>;
10391039

1040+
def err_objc_direct_on_protocol : Error<
1041+
"'objc_direct' attribute cannot be applied to %select{methods|properties}0 "
1042+
"declared in an Objective-C protocol">;
1043+
def err_objc_direct_missing_on_decl : Error<
1044+
"direct method implementation was previously declared not direct">;
1045+
def err_objc_direct_on_override : Error<
1046+
"methods that %select{override superclass methods|implement protocol requirements}0 cannot be direct">;
1047+
def err_objc_override_direct_method : Error<
1048+
"cannot override a method that is declared direct by a superclass">;
1049+
def warn_objc_direct_ignored : Warning<
1050+
"%0 attribute isn't implemented by this Objective-C runtime">,
1051+
InGroup<IgnoredAttributes>;
1052+
def warn_objc_direct_property_ignored : Warning<
1053+
"direct attribute on property %0 ignored (not implemented by this Objective-C runtime)">,
1054+
InGroup<IgnoredAttributes>;
1055+
10401056
def warn_conflicting_overriding_ret_types : Warning<
10411057
"conflicting return type in "
10421058
"declaration of %0%diff{: $ vs $|}1,2">,
@@ -1122,6 +1138,7 @@ def warn_accessor_property_type_mismatch : Warning<
11221138
"type of property %0 does not match type of accessor %1">;
11231139
def note_conv_function_declared_at : Note<"type conversion function declared here">;
11241140
def note_method_declared_at : Note<"method %0 declared here">;
1141+
def note_direct_method_declared_at : Note<"direct method %0 declared here">;
11251142
def note_property_attribute : Note<"property %0 is declared "
11261143
"%select{deprecated|unavailable|partial}1 here">;
11271144
def err_setter_type_void : Error<"type of setter must be void">;
@@ -1363,6 +1380,8 @@ def warn_multiple_selectors: Warning<
13631380
"several methods with selector %0 of mismatched types are found "
13641381
"for the @selector expression">,
13651382
InGroup<SelectorTypeMismatch>, DefaultIgnore;
1383+
def err_direct_selector_expression: Error<
1384+
"@selector expression formed with direct selector %0">;
13661385

13671386
def err_objc_kindof_nonobject : Error<
13681387
"'__kindof' specifier cannot be applied to non-object type %0">;
@@ -1376,6 +1395,12 @@ def err_objc_method_unsupported_param_ret_type : Error<
13761395
def warn_messaging_unqualified_id : Warning<
13771396
"messaging unqualified id">, DefaultIgnore,
13781397
InGroup<DiagGroup<"objc-messaging-id">>;
1398+
def err_messaging_unqualified_id_with_direct_method : Error<
1399+
"messaging unqualified id with a method that is possibly direct">;
1400+
def err_messaging_super_with_direct_method : Error<
1401+
"messaging super with a direct method">;
1402+
def err_messaging_class_with_direct_method : Error<
1403+
"messaging a Class with a method that is possibly direct">;
13791404

13801405
// C++ declarations
13811406
def err_static_assert_expression_is_not_constant : Error<

clang/include/clang/Basic/ObjCRuntime.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,20 @@ class ObjCRuntime {
446446
llvm_unreachable("bad kind");
447447
}
448448

449+
/// Does this runtime supports direct dispatch
450+
bool allowsDirectDispatch() const {
451+
switch (getKind()) {
452+
case FragileMacOSX: return false;
453+
case MacOSX: return true;
454+
case iOS: return true;
455+
case WatchOS: return true;
456+
case GCC: return false;
457+
case GNUstep: return false;
458+
case ObjFW: return false;
459+
}
460+
llvm_unreachable("bad kind");
461+
}
462+
449463
/// Try to parse an Objective-C runtime specification from the given
450464
/// string.
451465
///

clang/include/clang/Sema/DeclSpec.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,8 @@ class ObjCDeclSpec {
833833
DQ_PR_unsafe_unretained = 0x800,
834834
DQ_PR_nullability = 0x1000,
835835
DQ_PR_null_resettable = 0x2000,
836-
DQ_PR_class = 0x4000
836+
DQ_PR_class = 0x4000,
837+
DQ_PR_direct = 0x8000,
837838
};
838839

839840
ObjCDeclSpec()
@@ -903,7 +904,7 @@ class ObjCDeclSpec {
903904
unsigned objcDeclQualifier : 7;
904905

905906
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
906-
unsigned PropertyAttributes : 15;
907+
unsigned PropertyAttributes : 16;
907908

908909
unsigned Nullability : 2;
909910

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8969,6 +8969,9 @@ class Sema {
89698969
checkRelatedResultTypeCompatibility(const ObjCMethodDecl *Method,
89708970
const ObjCInterfaceDecl *CurrentClass);
89718971

8972+
void CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
8973+
ObjCMethodDecl *overridden);
8974+
89728975
void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
89738976
ObjCInterfaceDecl *CurrentClass,
89748977
ResultTypeCompatibilityKind RTC);

clang/lib/AST/DeclObjC.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
823823
Selector(), QualType(), nullptr, nullptr);
824824
}
825825

826+
bool ObjCMethodDecl::isDirectMethod() const {
827+
return hasAttr<ObjCDirectAttr>();
828+
}
829+
826830
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
827831
return getMethodFamily() == OMF_init &&
828832
hasAttr<ObjCDesignatedInitializerAttr>();
@@ -1077,7 +1081,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
10771081
QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
10781082
const ObjCInterfaceDecl *OID,
10791083
bool &selfIsPseudoStrong,
1080-
bool &selfIsConsumed) {
1084+
bool &selfIsConsumed) const {
10811085
QualType selfTy;
10821086
selfIsPseudoStrong = false;
10831087
selfIsConsumed = false;

clang/lib/AST/DeclPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
14741474
first = false;
14751475
}
14761476

1477+
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_direct) {
1478+
Out << (first ? "" : ", ") << "direct";
1479+
first = false;
1480+
}
1481+
14771482
if (PDecl->getPropertyAttributes() &
14781483
ObjCPropertyDecl::OBJC_PR_nonatomic) {
14791484
Out << (first ? "" : ", ") << "nonatomic";

clang/lib/AST/JSONNodeDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
10131013
attributeOnlyIfTrue("unsafe_unretained",
10141014
Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
10151015
attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class);
1016+
attributeOnlyIfTrue("direct", Attrs & ObjCPropertyDecl::OBJC_PR_direct);
10161017
attributeOnlyIfTrue("nullability",
10171018
Attrs & ObjCPropertyDecl::OBJC_PR_nullability);
10181019
attributeOnlyIfTrue("null_resettable",

0 commit comments

Comments
 (0)