Skip to content

Commit 1bb2186

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 3baba0b commit 1bb2186

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
@@ -4156,6 +4156,10 @@ void ValueDecl::setIsObjC(bool value) {
41564156
}
41574157

41584158
Identifier ExtensionDecl::getObjCCategoryName() const {
4159+
auto abiRole = ABIRoleInfo(this);
4160+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4161+
return abiRole.getCounterpart()->getObjCCategoryName();
4162+
41594163
// If there's an @objc attribute, it's authoritative. (ClangImporter
41604164
// attaches one automatically.)
41614165
if (auto objcAttr = getAttrs().getAttribute<ObjCAttr>(/*AllowInvalid*/true)) {
@@ -4409,6 +4413,10 @@ StringRef ValueDecl::getCDeclName() const {
44094413
return clangDecl->getName();
44104414
}
44114415

4416+
auto abiRole = ABIRoleInfo(this);
4417+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4418+
return abiRole.getCounterpart()->getCDeclName();
4419+
44124420
// Handle explicit cdecl attributes.
44134421
if (auto cdeclAttr = getAttrs().getAttribute<CDeclAttr>()) {
44144422
return cdeclAttr->Name;
@@ -4447,6 +4455,10 @@ ValueDecl::getObjCRuntimeName(bool skipIsObjCResolution) const {
44474455

44484456
std::optional<ObjCSelector>
44494457
Decl::getExplicitObjCName(bool allowInvalid) const {
4458+
auto abiRole = ABIRoleInfo(this);
4459+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
4460+
return abiRole.getCounterpart()->getExplicitObjCName();
4461+
44504462
auto objcAttr = getAttrs().getAttribute<ObjCAttr>(allowInvalid);
44514463
if (objcAttr && !objcAttr->isNameImplicit())
44524464
return objcAttr->getName();
@@ -5141,6 +5153,10 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC,
51415153
static bool
51425154
isObjCMemberImplementation(const ValueDecl *VD,
51435155
llvm::function_ref<AccessLevel()> getAccessLevel) {
5156+
auto abiRole = ABIRoleInfo(VD);
5157+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
5158+
return isObjCMemberImplementation(abiRole.getCounterpart(), getAccessLevel);
5159+
51445160
if (auto ED = dyn_cast<ExtensionDecl>(VD->getDeclContext()))
51455161
if (ED->isObjCImplementation() && !isa<TypeDecl>(VD)) {
51465162
auto attrDecl = isa<AccessorDecl>(VD)
@@ -6620,6 +6636,10 @@ static StringRef mangleObjCRuntimeName(const NominalTypeDecl *nominal,
66206636

66216637
StringRef ClassDecl::getObjCRuntimeName(
66226638
llvm::SmallVectorImpl<char> &buffer) const {
6639+
auto abiRole = ABIRoleInfo(this);
6640+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
6641+
return abiRole.getCounterpart()->getObjCRuntimeName(buffer);
6642+
66236643
// If there is a Clang declaration, use it's runtime name.
66246644
if (auto objcClass
66256645
= dyn_cast_or_null<clang::ObjCInterfaceDecl>(getClangDecl()))
@@ -7128,6 +7148,10 @@ ProtocolDecl::getPrimaryAssociatedTypes() const {
71287148

71297149
StringRef ProtocolDecl::getObjCRuntimeName(
71307150
llvm::SmallVectorImpl<char> &buffer) const {
7151+
auto abiRole = ABIRoleInfo(this);
7152+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7153+
return abiRole.getCounterpart()->getObjCRuntimeName(buffer);
7154+
71317155
// If there is an 'objc' attribute with a name, use that name.
71327156
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
71337157
if (auto name = objc->getName())
@@ -7600,6 +7624,10 @@ getNameFromObjcAttribute(const ObjCAttr *attr, DeclName preferredName) {
76007624

76017625
ObjCSelector
76027626
AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
7627+
auto abiRole = ABIRoleInfo(this);
7628+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7629+
return abiRole.getCounterpart()->getObjCGetterSelector(preferredName);
7630+
76037631
// If the getter has an @objc attribute with a name, use that.
76047632
if (auto getter = getAccessor(AccessorKind::Get)) {
76057633
if (auto name = getNameFromObjcAttribute(getter->getAttrs().
@@ -7630,6 +7658,10 @@ AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
76307658

76317659
ObjCSelector
76327660
AbstractStorageDecl::getObjCSetterSelector(Identifier preferredName) const {
7661+
auto abiRole = ABIRoleInfo(this);
7662+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
7663+
return abiRole.getCounterpart()->getObjCSetterSelector(preferredName);
7664+
76337665
// If the setter has an @objc attribute with a name, use that.
76347666
auto setter = getAccessor(AccessorKind::Set);
76357667
auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
@@ -8617,6 +8649,10 @@ Type VarDecl::getPropertyWrapperInitValueInterfaceType() const {
86178649
}
86188650

86198651
Identifier VarDecl::getObjCPropertyName() const {
8652+
auto abiRole = ABIRoleInfo(this);
8653+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
8654+
return abiRole.getCounterpart()->getObjCPropertyName();
8655+
86208656
if (auto attr = getAttrs().getAttribute<ObjCAttr>()) {
86218657
if (auto name = attr->getName())
86228658
return name->getSelectorPieces()[0];
@@ -10221,6 +10257,11 @@ AbstractFunctionDecl::getBodyFingerprintIncludingLocalTypeMembers() const {
1022110257
ObjCSelector
1022210258
AbstractFunctionDecl::getObjCSelector(DeclName preferredName,
1022310259
bool skipIsObjCResolution) const {
10260+
auto abiRole = ABIRoleInfo(this);
10261+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
10262+
return abiRole.getCounterpart()->getObjCSelector(preferredName,
10263+
skipIsObjCResolution);
10264+
1022410265
// FIXME: Forces computation of the Objective-C selector.
1022510266
if (!skipIsObjCResolution)
1022610267
(void)isObjC();
@@ -11652,7 +11693,12 @@ bool ClassDecl::isNonDefaultExplicitDistributedActor(ModuleDecl *M,
1165211693
bool ClassDecl::isNativeNSObjectSubclass() const {
1165311694
// @objc actors implicitly inherit from NSObject.
1165411695
if (isActor()) {
11655-
if (getAttrs().hasAttribute<ObjCAttr>()) {
11696+
DeclAttributes attrs = getAttrs();
11697+
auto abiRole = ABIRoleInfo(this);
11698+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
11699+
attrs = abiRole.getCounterpart()->getAttrs();
11700+
11701+
if (attrs.hasAttribute<ObjCAttr>()) {
1165611702
return true;
1165711703
}
1165811704
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
@@ -6594,6 +6594,9 @@ findFunctionInterfaceAndImplementation(AbstractFunctionDecl *func) {
65946594

65956595
ObjCInterfaceAndImplementation ObjCInterfaceAndImplementationRequest::
65966596
evaluate(Evaluator &evaluator, Decl *decl) const {
6597+
ASSERT(ABIRoleInfo(decl).providesAPI()
6598+
&& "@interface request for ABI-only decl?");
6599+
65976600
// Types and extensions have direct links to their counterparts through the
65986601
// `@_objcImplementation` attribute. Let's resolve that.
65996602
// (Also directing nulls here, where they'll early-return.)
@@ -6633,6 +6636,21 @@ llvm::TinyPtrVector<Decl *> Decl::getAllImplementedObjCDecls() const {
66336636
// This *is* the interface, if there is one.
66346637
return {};
66356638

6639+
// ABI-only attributes don't have an `@implementation`, so query the API
6640+
// counterpart and map the results back to ABI decls.
6641+
auto abiRole = ABIRoleInfo(this);
6642+
if (!abiRole.providesAPI() && abiRole.getCounterpart()) {
6643+
auto interfaceDecls =
6644+
abiRole.getCounterpart()->getAllImplementedObjCDecls();
6645+
6646+
// Map the APIs back to their ABI counterparts (often a no-op)
6647+
for (auto &interfaceDecl : interfaceDecls) {
6648+
interfaceDecl = ABIRoleInfo(interfaceDecl).getCounterpart();
6649+
}
6650+
6651+
return interfaceDecls;
6652+
}
6653+
66366654
ObjCInterfaceAndImplementationRequest req{const_cast<Decl *>(this)};
66376655
auto result = evaluateOrDefault(getASTContext().evaluator, req, {});
66386656
return result.interfaceDecls;
@@ -6650,6 +6668,14 @@ Decl *Decl::getObjCImplementationDecl() const {
66506668
// This *is* the implementation, if it has one.
66516669
return nullptr;
66526670

6671+
// ABI-only attributes don't have an `@implementation`, so query the API
6672+
// counterpart and map the results back to ABI decls.
6673+
auto abiRole = ABIRoleInfo(this);
6674+
if (!abiRole.providesAPI() && abiRole.getCounterpart()) {
6675+
auto implDecl = abiRole.getCounterpart()->getObjCImplementationDecl();
6676+
return ABIRoleInfo(implDecl).getCounterpart();
6677+
}
6678+
66536679
ObjCInterfaceAndImplementationRequest req{const_cast<Decl *>(this)};
66546680
auto result = evaluateOrDefault(getASTContext().evaluator, req, {});
66556681
return result.implementationDecl;

lib/Sema/TypeCheckAttr.cpp

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

16631663
void AttributeChecker::
16641664
visitObjCImplementationAttr(ObjCImplementationAttr *attr) {
1665+
// If `D` is ABI-only, let ABIDeclChecker diagnose the bad attribute.
1666+
if (!ABIRoleInfo(D).providesAPI())
1667+
return;
1668+
16651669
DeclAttribute * langAttr =
16661670
D->getAttrs().getAttribute<ObjCAttr>(/*AllowInvalid=*/true);
16671671
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

@@ -4115,6 +4133,9 @@ class ObjCImplementationChecker {
41154133

41164134
evaluator::SideEffect TypeCheckObjCImplementationRequest::
41174135
evaluate(Evaluator &evaluator, Decl *D) const {
4136+
if (!ABIRoleInfo(D).providesAPI())
4137+
return evaluator::SideEffect();
4138+
41184139
PrettyStackTraceDecl trace("checking member implementations of", D);
41194140

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

0 commit comments

Comments
 (0)