Skip to content

Commit 94ff062

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 c9f539e commit 94ff062

21 files changed

+735
-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
@@ -2914,6 +2914,31 @@ class AllowFeatureSuppressionAttr final
29142914
UNIMPLEMENTED_CLONE(AllowFeatureSuppressionAttr)
29152915
};
29162916

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

include/swift/AST/Decl.h

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

2665+
/// Returns the \c VarDecl in this PBD at the same offset in the same
2666+
/// pattern entry as \p otherVar is in its PBD, or \c nullptr if this PBD is
2667+
/// too different from \p otherVar 's to find an equivalent variable.
2668+
VarDecl *getVarAtSimilarStructuralPosition(VarDecl *otherVar);
2669+
26652670
static bool classof(const Decl *D) {
26662671
return D->getKind() == DeclKind::PatternBinding;
26672672
}

include/swift/AST/DeclAttr.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,11 @@ DECL_ATTR(safe, Safe,
523523
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
524524
163)
525525

526-
LAST_DECL_ATTR(Safe)
526+
DECL_ATTR(abi, ABI,
527+
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
528+
164)
529+
530+
LAST_DECL_ATTR(ABI)
527531

528532
#undef DECL_ATTR_ALIAS
529533
#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);
@@ -3862,6 +3863,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
38623863

38633864
#undef TRIVIAL_ATTR_PRINTER
38643865

3866+
void visitABIAttr(ABIAttr *Attr, StringRef label) {
3867+
printCommon(Attr, "abi_attr", label);
3868+
printRec(Attr->abiDecl, "decl");
3869+
printFoot();
3870+
}
38653871
void visitAccessControlAttr(AccessControlAttr *Attr, StringRef label) {
38663872
printCommon(Attr, "access_control_attr", label);
38673873
printField(Attr->getAccess(), "access_level");

lib/AST/Attr.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,16 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
16451645
break;
16461646
}
16471647

1648+
case DeclAttrKind::ABI: {
1649+
auto *attr = cast<ABIAttr>(this);
1650+
Printer << "@abi(";
1651+
if (attr->abiDecl)
1652+
attr->abiDecl->print(Printer, Options);
1653+
Printer << ")";
1654+
1655+
break;
1656+
}
1657+
16481658
#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DeclAttrKind::CLASS:
16491659
#include "swift/AST/DeclAttr.def"
16501660
llvm_unreachable("handled above");
@@ -1690,6 +1700,8 @@ StringRef DeclAttribute::getAttrName() const {
16901700
case DeclAttrKind::CLASS: \
16911701
return #NAME;
16921702
#include "swift/AST/DeclAttr.def"
1703+
case DeclAttrKind::ABI:
1704+
return "abi";
16931705
case DeclAttrKind::SILGenName:
16941706
return "_silgen_name";
16951707
case DeclAttrKind::Alignment:
@@ -2869,6 +2881,30 @@ LifetimeAttr *LifetimeAttr::create(ASTContext &context, SourceLoc atLoc,
28692881
return new (context) LifetimeAttr(atLoc, baseRange, implicit, entry);
28702882
}
28712883

2884+
void ASTContext::recordABIAttr(ABIAttr *attr, Decl *owner) {
2885+
// The ABIAttr on a VarDecl ought to point to its PBD.
2886+
if (auto VD = dyn_cast<VarDecl>(owner)) {
2887+
if (auto PBD = VD->getParentPatternBinding()) {
2888+
owner = PBD;
2889+
}
2890+
}
2891+
2892+
auto recordABIDecl = [&](Decl *decl) {
2893+
ABIDeclCounterparts.insert({ decl, owner });
2894+
};
2895+
2896+
if (auto abiPBD = dyn_cast<PatternBindingDecl>(attr->abiDecl)) {
2897+
// Add to *every* VarDecl in the ABI PBD, even ones that don't properly
2898+
// match anything in the API PBD.
2899+
for (auto i : range(abiPBD->getNumPatternEntries())) {
2900+
abiPBD->getPattern(i)->forEachVariable(recordABIDecl);
2901+
}
2902+
return;
2903+
}
2904+
2905+
recordABIDecl(attr->abiDecl);
2906+
}
2907+
28722908
void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
28732909
if (attr)
28742910
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
}
@@ -4268,6 +4270,43 @@ void ValueDecl::setRenamedDecl(const AvailableAttr *attr,
42684270
std::move(renameDecl));
42694271
}
42704272

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

0 commit comments

Comments
 (0)