Skip to content

Commit 27a6061

Browse files
committed
Parse and serialize @abi attribute
This attribute will allow you to specify an alternate version of the declaration used for mangling. It will allow minor adjustments to be made to declarations so long as they’re still compatible at the calling convention level, such as refining isolation or sendability, renaming without breaking ABI, etc. The attribute is behind the experimental feature flag `ABIAttribute`.
1 parent b0b459a commit 27a6061

21 files changed

+736
-82
lines changed

include/swift/AST/ASTContext.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ namespace llvm {
6767
}
6868

6969
namespace swift {
70+
class ABIAttr;
7071
class AbstractFunctionDecl;
7172
class ASTContext;
7273
enum class Associativity : unsigned char;
@@ -414,6 +415,19 @@ class ASTContext final {
414415
llvm::SmallPtrSet<DerivativeAttr *, 1>>
415416
DerivativeAttrs;
416417

418+
/// For each ABI-only declaration (created with the `@abi` attribute), points
419+
/// to its API-only counterpart. That is, this table maps each
420+
/// `ABIAttr::abiDecl` to the declaration the `ABIAttr` is attached to.
421+
///
422+
/// \seeAlso \c recordABIAttr()
423+
llvm::DenseMap<Decl *, Decl *> ABIDeclCounterparts;
424+
425+
/// Register \c this->abiDecl 's relationship with \p owner in
426+
/// `ABIDeclCounterparts` . This is necessary for
427+
/// \c ABIRoleInfo::ABIRoleInfo() to determine that \c this->abiDecl
428+
/// is ABI-only and locate its API counterpart.
429+
void recordABIAttr(ABIAttr *attr, Decl *owner);
430+
417431
/// The Swift module currently being compiled.
418432
ModuleDecl *MainModule = nullptr;
419433

include/swift/AST/Attr.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,31 @@ class AllowFeatureSuppressionAttr final
29102910
UNIMPLEMENTED_CLONE(AllowFeatureSuppressionAttr)
29112911
};
29122912

2913+
/// Defines the @abi attribute.
2914+
class ABIAttr : public DeclAttribute {
2915+
public:
2916+
ABIAttr(Decl *abiDecl, SourceLoc AtLoc, SourceRange Range, bool Implicit)
2917+
: DeclAttribute(DeclAttrKind::ABI, AtLoc, Range, Implicit),
2918+
abiDecl(abiDecl)
2919+
{ }
2920+
2921+
ABIAttr(Decl *abiDecl, bool Implicit)
2922+
: ABIAttr(abiDecl, SourceLoc(), SourceRange(), Implicit) {}
2923+
2924+
/// The declaration which will be used to compute a mangled name.
2925+
///
2926+
/// \note For a \c VarDecl with a parent \c PatternBindingDecl , this should
2927+
/// point to the parent \c PatternBindingDecl . (That accommodates the way
2928+
/// sibling \c VarDecl s share attributes.)
2929+
Decl *abiDecl;
2930+
2931+
static bool classof(const DeclAttribute *DA) {
2932+
return DA->getKind() == DeclAttrKind::ABI;
2933+
}
2934+
2935+
UNIMPLEMENTED_CLONE(ABIAttr)
2936+
};
2937+
29132938
/// Attributes that may be applied to declarations.
29142939
class DeclAttributes {
29152940
/// Linked list of declaration attributes.

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,11 @@ class PatternBindingDecl final : public Decl,
26482648
/// Returns \c true if this pattern binding was created by the debugger.
26492649
bool isDebuggerBinding() const { return Bits.PatternBindingDecl.IsDebugger; }
26502650

2651+
/// Returns the \c VarDecl in this PBD at the same offset in the same
2652+
/// pattern entry as \p otherVar is in its PBD, or \c nullptr if this PBD is
2653+
/// too different from \p otherVar 's to find an equivalent variable.
2654+
VarDecl *getVarAtSimilarStructuralPosition(VarDecl *otherVar);
2655+
26512656
static bool classof(const Decl *D) {
26522657
return D->getKind() == DeclKind::PatternBinding;
26532658
}

include/swift/AST/DeclAttr.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,11 @@ SIMPLE_DECL_ATTR(_addressableSelf, AddressableSelf,
517517
OnAccessor | OnConstructor | OnFunc | OnSubscript | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | UserInaccessible,
518518
162)
519519

520-
LAST_DECL_ATTR(AddressableSelf)
520+
DECL_ATTR(abi, ABI,
521+
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
522+
163)
523+
524+
LAST_DECL_ATTR(ABI)
521525

522526
#undef DECL_ATTR_ALIAS
523527
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ ERROR(let_cannot_be_addressed_property,none,
228228
ERROR(disallowed_var_multiple_getset,none,
229229
"'var' declarations with multiple variables cannot have explicit"
230230
" getters/setters", ())
231+
ERROR(stub_decl_cannot_have_body,none,
232+
"stub %0 cannot have body",
233+
(DescriptiveDeclKind))
231234

232235
ERROR(disallowed_init,none,
233236
"initial value is not allowed here", ())

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,9 @@ EXPERIMENTAL_FEATURE(GenerateForceToMainActorThunks, false)
436436

437437
EXPERIMENTAL_FEATURE(AddressableParameters, true)
438438

439+
/// Allow the @abi attribute.
440+
EXPERIMENTAL_FEATURE(ABIAttribute, true)
441+
439442
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
440443
#undef EXPERIMENTAL_FEATURE
441444
#undef UPCOMING_FEATURE

include/swift/Parse/Parser.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ class Parser {
933933
bool isStartOfGetSetAccessor();
934934

935935
/// Flags that control the parsing of declarations.
936-
enum ParseDeclFlags {
936+
enum ParseDeclFlags : uint16_t {
937937
PD_Default = 0,
938938
PD_AllowTopLevel = 1 << 1,
939939
PD_HasContainerType = 1 << 2,
@@ -944,6 +944,7 @@ class Parser {
944944
PD_InExtension = 1 << 7,
945945
PD_InStruct = 1 << 8,
946946
PD_InEnum = 1 << 9,
947+
PD_StubOnly = 1 << 10,
947948
};
948949

949950
/// Options that control the parsing of declarations.
@@ -953,20 +954,24 @@ class Parser {
953954

954955
ParserStatus parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
955956
bool IfConfigsAreDeclAttrs,
956-
llvm::function_ref<void(Decl *)> Handler);
957+
llvm::function_ref<void(Decl *)> Handler,
958+
bool stubOnly = false);
957959

958960
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
959961
parseDeclListDelayed(IterableDeclContext *IDC);
960962

961963
bool parseMemberDeclList(SourceLoc &LBLoc, SourceLoc &RBLoc,
962964
Diag<> LBraceDiag, Diag<> RBraceDiag,
963-
IterableDeclContext *IDC);
965+
IterableDeclContext *IDC,
966+
ParseDeclOptions Flags);
964967

965968
bool canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
966969
bool &HasNestedClassDeclarations,
967-
bool &HasDerivativeDeclarations);
970+
bool &HasDerivativeDeclarations,
971+
ParseDeclOptions Flags);
968972

969-
bool canDelayFunctionBodyParsing(bool &HasNestedTypeDeclarations);
973+
bool canDelayFunctionBodyParsing(bool &HasNestedTypeDeclarations,
974+
ParseDeclOptions Flags);
970975

971976
bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
972977
IterableDeclContext *IDC);
@@ -1318,7 +1323,8 @@ class Parser {
13181323
bool HasFuncKeyword = true);
13191324
BodyAndFingerprint
13201325
parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD);
1321-
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD);
1326+
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD,
1327+
ParseDeclOptions Flags);
13221328
BodyAndFingerprint
13231329
parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
13241330

lib/AST/ASTDumper.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -967,9 +967,10 @@ namespace {
967967
}
968968

969969
/// Print an unnamed field containing a node's name, read from a declaration.
970-
void printDeclName(const ValueDecl *D, bool leadingSpace = true) {
971-
if (D->getName()) {
972-
printName(D->getName(), leadingSpace);
970+
void printDeclName(const Decl *D, bool leadingSpace = true) {
971+
auto VD = dyn_cast<ValueDecl>(D);
972+
if (VD && VD->getName()) {
973+
printName(VD->getName(), leadingSpace);
973974
} else {
974975
if (leadingSpace)
975976
OS << ' ';
@@ -979,7 +980,7 @@ namespace {
979980
}
980981

981982
/// Print a field containing a node's name, read from a declaration.
982-
void printDeclNameField(const ValueDecl *D, StringRef name) {
983+
void printDeclNameField(const Decl *D, StringRef name) {
983984
printFieldRaw([&](raw_ostream &os) {
984985
printDeclName(D, /*leadingSpace=*/false);
985986
}, name);
@@ -3856,6 +3857,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
38563857

38573858
#undef TRIVIAL_ATTR_PRINTER
38583859

3860+
void visitABIAttr(ABIAttr *Attr, StringRef label) {
3861+
printCommon(Attr, "abi_attr", label);
3862+
printRec(Attr->abiDecl, "decl");
3863+
printFoot();
3864+
}
38593865
void visitAccessControlAttr(AccessControlAttr *Attr, StringRef label) {
38603866
printCommon(Attr, "access_control_attr", label);
38613867
printField(Attr->getAccess(), "access_level");

lib/AST/Attr.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
10221022
}
10231023
break;
10241024
}
1025+
10251026
default:
10261027
break;
10271028
}
@@ -1584,6 +1585,16 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
15841585
break;
15851586
}
15861587

1588+
case DeclAttrKind::ABI: {
1589+
auto *attr = cast<ABIAttr>(this);
1590+
Printer << "@abi(";
1591+
if (attr->abiDecl)
1592+
attr->abiDecl->print(Printer, Options);
1593+
Printer << ")";
1594+
1595+
break;
1596+
}
1597+
15871598
#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS:
15881599
#include "swift/AST/DeclAttr.def"
15891600
llvm_unreachable("handled above");
@@ -1629,6 +1640,8 @@ StringRef DeclAttribute::getAttrName() const {
16291640
case DeclAttrKind::CLASS: \
16301641
return #NAME;
16311642
#include "swift/AST/DeclAttr.def"
1643+
case DeclAttrKind::ABI:
1644+
return "abi";
16321645
case DeclAttrKind::SILGenName:
16331646
return "_silgen_name";
16341647
case DeclAttrKind::Alignment:
@@ -2832,6 +2845,30 @@ LifetimeAttr *LifetimeAttr::create(ASTContext &context, SourceLoc atLoc,
28322845
return new (context) LifetimeAttr(atLoc, baseRange, implicit, entry);
28332846
}
28342847

2848+
void ASTContext::recordABIAttr(ABIAttr *attr, Decl *owner) {
2849+
// The ABIAttr on a VarDecl ought to point to its PBD.
2850+
if (auto VD = dyn_cast<VarDecl>(owner)) {
2851+
if (auto PBD = VD->getParentPatternBinding()) {
2852+
owner = PBD;
2853+
}
2854+
}
2855+
2856+
auto recordABIDecl = [&](Decl *decl) {
2857+
ABIDeclCounterparts.insert({ decl, owner });
2858+
};
2859+
2860+
if (auto abiPBD = dyn_cast<PatternBindingDecl>(attr->abiDecl)) {
2861+
// Add to *every* VarDecl in the ABI PBD, even ones that don't properly
2862+
// match anything in the API PBD.
2863+
for (auto i : range(abiPBD->getNumPatternEntries())) {
2864+
abiPBD->getPattern(i)->forEachVariable(recordABIDecl);
2865+
}
2866+
return;
2867+
}
2868+
2869+
recordABIDecl(attr->abiDecl);
2870+
}
2871+
28352872
void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
28362873
if (attr)
28372874
attr->print(out);

lib/AST/Decl.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ void Decl::attachParsedAttrs(DeclAttributes attrs) {
414414
attr->setOriginalDeclaration(this);
415415
for (auto *attr : attrs.getAttributes<DerivativeAttr>())
416416
attr->setOriginalDeclaration(this);
417+
for (auto attr : attrs.getAttributes<ABIAttr, /*AllowInvalid=*/true>())
418+
this->getASTContext().recordABIAttr(attr, this);
417419

418420
getAttrs() = attrs;
419421
}
@@ -4264,6 +4266,43 @@ void ValueDecl::setRenamedDecl(const AvailableAttr *attr,
42644266
std::move(renameDecl));
42654267
}
42664268

4269+
VarDecl *PatternBindingDecl::
4270+
getVarAtSimilarStructuralPosition(VarDecl *otherVar) {
4271+
auto otherPBD = otherVar->getParentPatternBinding();
4272+
4273+
if (!otherPBD)
4274+
return getSingleVar();
4275+
if (otherPBD == this)
4276+
return otherVar;
4277+
4278+
// Find the entry index and sibling index for `otherVar` within its PBD.
4279+
auto entryIndex = otherPBD->getPatternEntryIndexForVarDecl(otherVar);
4280+
4281+
SmallVector<VarDecl *, 16> otherSiblings;
4282+
otherPBD->getPattern(entryIndex)->collectVariables(otherSiblings);
4283+
size_t siblingIndex =
4284+
llvm::find(otherSiblings, otherVar) - otherSiblings.begin();
4285+
4286+
ASSERT(siblingIndex != otherSiblings.size()
4287+
&& "otherVar not in its own pattern?");
4288+
4289+
// Look up the same entry index and sibling index in this PBD, returning null
4290+
// if that index doesn't exist.
4291+
4292+
// Corresponding PBD has more patterns in it
4293+
if (entryIndex >= getNumPatternEntries())
4294+
return nullptr;
4295+
4296+
SmallVector<VarDecl *, 16> siblings;
4297+
getPattern(entryIndex)->collectVariables(siblings);
4298+
4299+
// Corresponding pattern has more vars in it
4300+
if (siblingIndex >= siblings.size())
4301+
return nullptr;
4302+
4303+
return siblings[siblingIndex];
4304+
}
4305+
42674306
SourceLoc Decl::getAttributeInsertionLoc(bool forModifier) const {
42684307
// Some decls have a parent/child split where the introducer keyword is on the
42694308
// parent, but the attributes are on the children. If this is a child in such

0 commit comments

Comments
 (0)