Skip to content

Commit f4e0ae6

Browse files
committed
Inherit @objc, dynamic, @implementation in @abi
ABI-only declarations now query their API counterpart for things like `isObjC()`, their ObjC name, dynamic status, etc. This means that `@objc` and friends can simply be omitted from an `@abi` attribute. No tests in this commit since attribute checking hasn’t landed yet.
1 parent 4a3d09d commit f4e0ae6

File tree

7 files changed

+130
-2
lines changed

7 files changed

+130
-2
lines changed

lib/AST/Decl.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4058,6 +4058,10 @@ void ValueDecl::setIsObjC(bool value) {
40584058
}
40594059

40604060
Identifier ExtensionDecl::getObjCCategoryName() const {
4061+
auto abiRole = ABIRoleInfo(this);
4062+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4063+
return abiRole.getCounterpart()->getObjCCategoryName();
4064+
40614065
// If there's an @objc attribute, it's authoritative. (ClangImporter
40624066
// attaches one automatically.)
40634067
if (auto objcAttr = getAttrs().getAttribute<ObjCAttr>(/*AllowInvalid*/true)) {
@@ -4293,6 +4297,10 @@ StringRef ValueDecl::getCDeclName() const {
42934297
return clangDecl->getName();
42944298
}
42954299

4300+
auto abiRole = ABIRoleInfo(this);
4301+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4302+
return abiRole.getCounterpart()->getCDeclName();
4303+
42964304
// Handle explicit cdecl attributes.
42974305
if (auto cdeclAttr = getAttrs().getAttribute<CDeclAttr>()) {
42984306
return cdeclAttr->Name;
@@ -4331,6 +4339,10 @@ ValueDecl::getObjCRuntimeName(bool skipIsObjCResolution) const {
43314339

43324340
std::optional<ObjCSelector>
43334341
Decl::getExplicitObjCName(bool allowInvalid) const {
4342+
auto abiRole = ABIRoleInfo(this);
4343+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4344+
return abiRole.getCounterpart()->getExplicitObjCName();
4345+
43344346
auto objcAttr = getAttrs().getAttribute<ObjCAttr>(allowInvalid);
43354347
if (objcAttr && !objcAttr->isNameImplicit())
43364348
return objcAttr->getName();
@@ -5025,6 +5037,10 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC,
50255037
static bool
50265038
isObjCMemberImplementation(const ValueDecl *VD,
50275039
llvm::function_ref<AccessLevel()> getAccessLevel) {
5040+
auto abiRole = ABIRoleInfo(VD);
5041+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
5042+
return isObjCMemberImplementation(abiRole.getCounterpart(), getAccessLevel);
5043+
50285044
if (auto ED = dyn_cast<ExtensionDecl>(VD->getDeclContext()))
50295045
if (ED->isObjCImplementation() && !isa<TypeDecl>(VD)) {
50305046
auto attrDecl = isa<AccessorDecl>(VD)
@@ -6504,6 +6520,10 @@ static StringRef mangleObjCRuntimeName(const NominalTypeDecl *nominal,
65046520

65056521
StringRef ClassDecl::getObjCRuntimeName(
65066522
llvm::SmallVectorImpl<char> &buffer) const {
6523+
auto abiRole = ABIRoleInfo(this);
6524+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
6525+
return abiRole.getCounterpart()->getObjCRuntimeName(buffer);
6526+
65076527
// If there is a Clang declaration, use it's runtime name.
65086528
if (auto objcClass
65096529
= dyn_cast_or_null<clang::ObjCInterfaceDecl>(getClangDecl()))
@@ -7012,6 +7032,10 @@ ProtocolDecl::getPrimaryAssociatedTypes() const {
70127032

70137033
StringRef ProtocolDecl::getObjCRuntimeName(
70147034
llvm::SmallVectorImpl<char> &buffer) const {
7035+
auto abiRole = ABIRoleInfo(this);
7036+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7037+
return abiRole.getCounterpart()->getObjCRuntimeName(buffer);
7038+
70157039
// If there is an 'objc' attribute with a name, use that name.
70167040
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
70177041
if (auto name = objc->getName())
@@ -7484,6 +7508,10 @@ getNameFromObjcAttribute(const ObjCAttr *attr, DeclName preferredName) {
74847508

74857509
ObjCSelector
74867510
AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
7511+
auto abiRole = ABIRoleInfo(this);
7512+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7513+
return abiRole.getCounterpart()->getObjCGetterSelector(preferredName);
7514+
74877515
// If the getter has an @objc attribute with a name, use that.
74887516
if (auto getter = getAccessor(AccessorKind::Get)) {
74897517
if (auto name = getNameFromObjcAttribute(getter->getAttrs().
@@ -7514,6 +7542,10 @@ AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
75147542

75157543
ObjCSelector
75167544
AbstractStorageDecl::getObjCSetterSelector(Identifier preferredName) const {
7545+
auto abiRole = ABIRoleInfo(this);
7546+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7547+
return abiRole.getCounterpart()->getObjCSetterSelector(preferredName);
7548+
75177549
// If the setter has an @objc attribute with a name, use that.
75187550
auto setter = getAccessor(AccessorKind::Set);
75197551
auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
@@ -8501,6 +8533,10 @@ Type VarDecl::getPropertyWrapperInitValueInterfaceType() const {
85018533
}
85028534

85038535
Identifier VarDecl::getObjCPropertyName() const {
8536+
auto abiRole = ABIRoleInfo(this);
8537+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
8538+
return abiRole.getCounterpart()->getObjCPropertyName();
8539+
85048540
if (auto attr = getAttrs().getAttribute<ObjCAttr>()) {
85058541
if (auto name = attr->getName())
85068542
return name->getSelectorPieces()[0];
@@ -10119,6 +10155,11 @@ AbstractFunctionDecl::getBodyFingerprintIncludingLocalTypeMembers() const {
1011910155
ObjCSelector
1012010156
AbstractFunctionDecl::getObjCSelector(DeclName preferredName,
1012110157
bool skipIsObjCResolution) const {
10158+
auto abiRole = ABIRoleInfo(this);
10159+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
10160+
return abiRole.getCounterpart()->getObjCSelector(preferredName,
10161+
skipIsObjCResolution);
10162+
1012210163
// FIXME: Forces computation of the Objective-C selector.
1012310164
if (!skipIsObjCResolution)
1012410165
(void)isObjC();
@@ -11506,7 +11547,12 @@ bool ClassDecl::isNonDefaultExplicitDistributedActor(ModuleDecl *M,
1150611547
bool ClassDecl::isNativeNSObjectSubclass() const {
1150711548
// @objc actors implicitly inherit from NSObject.
1150811549
if (isActor()) {
11509-
if (getAttrs().hasAttribute<ObjCAttr>()) {
11550+
DeclAttributes attrs = getAttrs();
11551+
auto abiRole = ABIRoleInfo(this);
11552+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
11553+
attrs = abiRole.getCounterpart()->getAttrs();
11554+
11555+
if (attrs.hasAttribute<ObjCAttr>()) {
1151011556
return true;
1151111557
}
1151211558
ClassDecl *superclass = getSuperclassDecl();

lib/AST/SwiftNameTranslation.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ getNameForObjC(const ValueDecl *VD, CustomNamesOnly_t customNamesOnly) {
3737
assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) || isa<StructDecl>(VD) ||
3838
isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD) ||
3939
isa<TypeAliasDecl>(VD));
40+
auto abiRole = ABIRoleInfo(VD);
41+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
42+
return getNameForObjC(abiRole.getCounterpart(), customNamesOnly);
43+
4044
if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>()) {
4145
if (auto name = objc->getName()) {
4246
assert(name->getNumSelectorPieces() == 1);
@@ -63,6 +67,10 @@ getErrorDomainStringForObjC(const EnumDecl *ED) {
6367
// Should have already been diagnosed as diag::objc_enum_generic.
6468
assert(!ED->isGenericContext() && "Trying to bridge generic enum error to Obj-C");
6569

70+
auto abiRole = ABIRoleInfo(ED);
71+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
72+
return getErrorDomainStringForObjC(abiRole.getCounterpart());
73+
6674
SmallVector<const NominalTypeDecl *, 4> outerTypes;
6775
for (const NominalTypeDecl * D = ED;
6876
D != nullptr;
@@ -86,6 +94,11 @@ getErrorDomainStringForObjC(const EnumDecl *ED) {
8694
bool swift::objc_translation::
8795
printSwiftEnumElemNameInObjC(const EnumElementDecl *EL, llvm::raw_ostream &OS,
8896
Identifier PreferredName) {
97+
auto abiRole = ABIRoleInfo(EL);
98+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
99+
return printSwiftEnumElemNameInObjC(abiRole.getCounterpart(), OS,
100+
PreferredName);
101+
89102
StringRef ElemName = getNameForObjC(EL, CustomNamesOnly);
90103
if (!ElemName.empty()) {
91104
OS << ElemName;
@@ -104,6 +117,10 @@ printSwiftEnumElemNameInObjC(const EnumElementDecl *EL, llvm::raw_ostream &OS,
104117

105118
std::pair<Identifier, ObjCSelector> swift::objc_translation::
106119
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
120+
auto abiRole = ABIRoleInfo(VD);
121+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
122+
return getObjCNameForSwiftDecl(abiRole.getCounterpart(), PreferredName);
123+
107124
ASTContext &Ctx = VD->getASTContext();
108125
Identifier BaseName;
109126
if (PreferredName) {
@@ -157,6 +174,10 @@ isVisibleToObjC(const ValueDecl *VD, AccessLevel minRequiredAccess,
157174
StringRef
158175
swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
159176
CustomNamesOnly_t customNamesOnly) {
177+
auto abiRole = ABIRoleInfo(VD);
178+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
179+
return getNameForCxx(abiRole.getCounterpart(), customNamesOnly);
180+
160181
ASTContext& ctx = VD->getASTContext();
161182

162183
for (auto *EA : VD->getAttrs().getAttributes<ExposeAttr>()) {
@@ -214,6 +235,10 @@ swift::cxx_translation::DeclRepresentation
214235
swift::cxx_translation::getDeclRepresentation(
215236
const ValueDecl *VD,
216237
std::optional<std::function<bool(const NominalTypeDecl *)>> isZeroSized) {
238+
auto abiRole = ABIRoleInfo(VD);
239+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
240+
return getDeclRepresentation(abiRole.getCounterpart(), isZeroSized);
241+
217242
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
218243
return {Unsupported, UnrepresentableIsolatedInActor};
219244
if (isa<MacroDecl>(VD))

lib/AST/TypeCheckRequests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ void IsDynamicRequest::cacheResult(bool value) const {
356356
decl->setIsDynamic(value);
357357

358358
// Add an attribute for printing
359-
if (value && !decl->getAttrs().hasAttribute<DynamicAttr>())
359+
if (value && !decl->getAttrs().hasAttribute<DynamicAttr>() &&
360+
ABIRoleInfo(decl).providesAPI())
360361
decl->getAttrs().add(new (decl->getASTContext()) DynamicAttr(/*Implicit=*/true));
361362
}
362363

lib/ClangImporter/ClangImporter.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6518,6 +6518,9 @@ findFunctionInterfaceAndImplementation(AbstractFunctionDecl *func) {
65186518

65196519
ObjCInterfaceAndImplementation ObjCInterfaceAndImplementationRequest::
65206520
evaluate(Evaluator &evaluator, Decl *decl) const {
6521+
ASSERT(ABIRoleInfo(decl).providesAPI()
6522+
&& "@interface request for ABI-only decl?");
6523+
65216524
// Types and extensions have direct links to their counterparts through the
65226525
// `@_objcImplementation` attribute. Let's resolve that.
65236526
// (Also directing nulls here, where they'll early-return.)
@@ -6557,6 +6560,21 @@ llvm::TinyPtrVector<Decl *> Decl::getAllImplementedObjCDecls() const {
65576560
// This *is* the interface, if there is one.
65586561
return {};
65596562

6563+
// ABI-only attributes don't have an `@implementation`, so query the API
6564+
// counterpart and map the results back to ABI decls.
6565+
auto abiRole = ABIRoleInfo(this);
6566+
if (!abiRole.providesAPI() && abiRole.getCounterpart()) {
6567+
auto interfaceDecls =
6568+
abiRole.getCounterpart()->getAllImplementedObjCDecls();
6569+
6570+
// Map the APIs back to their ABI counterparts (often a no-op)
6571+
for (auto &interfaceDecl : interfaceDecls) {
6572+
interfaceDecl = ABIRoleInfo(interfaceDecl).getCounterpart();
6573+
}
6574+
6575+
return interfaceDecls;
6576+
}
6577+
65606578
ObjCInterfaceAndImplementationRequest req{const_cast<Decl *>(this)};
65616579
auto result = evaluateOrDefault(getASTContext().evaluator, req, {});
65626580
return result.interfaceDecls;
@@ -6574,6 +6592,14 @@ Decl *Decl::getObjCImplementationDecl() const {
65746592
// This *is* the implementation, if it has one.
65756593
return nullptr;
65766594

6595+
// ABI-only attributes don't have an `@implementation`, so query the API
6596+
// counterpart and map the results back to ABI decls.
6597+
auto abiRole = ABIRoleInfo(this);
6598+
if (!abiRole.providesAPI() && abiRole.getCounterpart()) {
6599+
auto implDecl = abiRole.getCounterpart()->getObjCImplementationDecl();
6600+
return ABIRoleInfo(implDecl).getCounterpart();
6601+
}
6602+
65776603
ObjCInterfaceAndImplementationRequest req{const_cast<Decl *>(this)};
65786604
auto result = evaluateOrDefault(getASTContext().evaluator, req, {});
65796605
return result.implementationDecl;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,10 @@ static SourceRange getArgListRange(ASTContext &Ctx, DeclAttribute *attr) {
17071707

17081708
void AttributeChecker::
17091709
visitObjCImplementationAttr(ObjCImplementationAttr *attr) {
1710+
// If `D` is ABI-only, let ABIDeclChecker diagnose the bad attribute.
1711+
if (!ABIRoleInfo(D).providesAPI())
1712+
return;
1713+
17101714
DeclAttribute * langAttr =
17111715
D->getAttrs().getAttribute<ObjCAttr>(/*AllowInvalid=*/true);
17121716
if (!langAttr)

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,11 @@ IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const {
938938

939939
bool
940940
IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
941+
// ABI-only decls get this from their API decl.
942+
auto abiRole = ABIRoleInfo(decl);
943+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
944+
return abiRole.getCounterpart()->isDynamic();
945+
941946
// If we can't infer dynamic here, don't.
942947
if (!DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::Dynamic, decl))
943948
return false;

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,11 @@ bool swift::isRepresentableInObjC(
650650
const AbstractFunctionDecl *AFD, ObjCReason Reason,
651651
std::optional<ForeignAsyncConvention> &asyncConvention,
652652
std::optional<ForeignErrorConvention> &errorConvention) {
653+
auto abiRole = ABIRoleInfo(AFD);
654+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
655+
return isRepresentableInObjC(abiRole.getCounterpart(), Reason,
656+
asyncConvention, errorConvention);
657+
653658
// Clear out the async and error conventions. They will be added later if
654659
// needed.
655660
asyncConvention = std::nullopt;
@@ -1104,6 +1109,10 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
11041109
if (VD->isInvalid())
11051110
return false;
11061111

1112+
auto abiRole = ABIRoleInfo(VD);
1113+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
1114+
return isRepresentableInObjC(abiRole.getCounterpart(), Reason);
1115+
11071116
Type T = VD->getDeclContext()->mapTypeIntoContext(VD->getInterfaceType());
11081117
if (auto *RST = T->getAs<ReferenceStorageType>()) {
11091118
// In-memory layout of @weak and @unowned does not correspond to anything
@@ -1160,6 +1169,10 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
11601169

11611170
bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) {
11621171
// If you change this function, you must add or modify a test in PrintAsClang.
1172+
auto abiRole = ABIRoleInfo(SD);
1173+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
1174+
return isRepresentableInObjC(abiRole.getCounterpart(), Reason);
1175+
11631176
ASTContext &ctx = SD->getASTContext();
11641177
DiagnosticStateRAII diagState(ctx.Diags);
11651178
auto behavior = behaviorLimitForObjCReason(Reason, ctx);
@@ -1770,6 +1783,11 @@ static void markAsObjC(ValueDecl *D, ObjCReason reason,
17701783
bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const {
17711784
DiagnosticStateRAII diagState(VD->getASTContext().Diags);
17721785

1786+
// ABI-only decls inherit objc-ness from their API.
1787+
auto abiRole = ABIRoleInfo(VD);
1788+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
1789+
return abiRole.getCounterpart()->isObjC();
1790+
17731791
// Access notes may add attributes that affect this calculus.
17741792
TypeChecker::applyAccessNote(VD);
17751793

@@ -4113,6 +4131,9 @@ class ObjCImplementationChecker {
41134131

41144132
evaluator::SideEffect TypeCheckObjCImplementationRequest::
41154133
evaluate(Evaluator &evaluator, Decl *D) const {
4134+
if (!ABIRoleInfo(D).providesAPI())
4135+
return evaluator::SideEffect();
4136+
41164137
PrettyStackTraceDecl trace("checking member implementations of", D);
41174138

41184139
// FIXME: Because we check extension-by-extension, candidates and requirements

0 commit comments

Comments
 (0)