Skip to content

Commit 7f8c04e

Browse files
committed
AST: introduce a new attribute @_originallDefinedIn to the AST
We need this attribute to teach compiler to use a different name from the current module name when generating runtime symbol names for a declaration. This is to serve the workflow of refactoring a symbol from one library to another without breaking the existing ABI. This patch focuses on parsing and serializing the attribute, so @_originallyDefinedIn will show up in AST, swiftinterface files and swiftmodule files. rdar://55268186
1 parent 8a61284 commit 7f8c04e

File tree

12 files changed

+292
-0
lines changed

12 files changed

+292
-0
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,12 @@ SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction,
513513
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
514514
95)
515515

516+
DECL_ATTR(_originallyDefinedIn, OriginallyDefinedIn,
517+
OnNominalType | OnFunc | OnVar | OnExtension | UserInaccessible |
518+
AllowMultipleAttributes |
519+
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
520+
96)
521+
516522
#undef TYPE_ATTR
517523
#undef DECL_ATTR_ALIAS
518524
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Attr.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,38 @@ class ProjectedValuePropertyAttr : public DeclAttribute {
15461546
}
15471547
};
15481548

1549+
/// Describe a symbol was originally defined in another module. For example, given
1550+
/// \code
1551+
/// @_originallyDefinedIn(module: "Original", OSX 10.15) var foo: Int
1552+
/// \endcode
1553+
///
1554+
/// Where variable Foo has originally defined in another module called Original prior to OSX 10.15
1555+
class OriginallyDefinedInAttr: public DeclAttribute {
1556+
public:
1557+
OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range,
1558+
StringRef OriginalModuleName,
1559+
PlatformKind Platform,
1560+
const llvm::VersionTuple MovedVersion,
1561+
bool Implicit)
1562+
: DeclAttribute(DAK_OriginallyDefinedIn, AtLoc, Range, Implicit),
1563+
OriginalModuleName(OriginalModuleName),
1564+
Platform(Platform),
1565+
MovedVersion(MovedVersion) {}
1566+
1567+
// The original module name.
1568+
const StringRef OriginalModuleName;
1569+
1570+
/// The platform of the symbol.
1571+
const PlatformKind Platform;
1572+
1573+
/// Indicates when the symbol was moved here.
1574+
const llvm::VersionTuple MovedVersion;
1575+
1576+
static bool classof(const DeclAttribute *DA) {
1577+
return DA->getKind() == DAK_OriginallyDefinedIn;
1578+
}
1579+
};
1580+
15491581
/// Attributes that may be applied to declarations.
15501582
class DeclAttributes {
15511583
/// Linked list of declaration attributes.

include/swift/AST/DiagnosticsParse.def

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,32 @@ WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
14101410
"unexpected version number in '%0' attribute for non-specific platform "
14111411
"'*'", (StringRef))
14121412

1413+
// originallyDefinedIn
1414+
ERROR(originally_defined_in_missing_rparen,none,
1415+
"expected ')' in @_originallyDefinedIn argument list", ())
1416+
1417+
ERROR(originally_defined_in_unrecognized_platform,none,
1418+
"unrecognized platform name in @_originallyDefinedIn argument list", ())
1419+
1420+
ERROR(originally_defined_in_unrecognized_property,none,
1421+
"unrecognized property in @_originallyDefinedIn argument list", ())
1422+
1423+
ERROR(originally_defined_in_need_original_module_name,none,
1424+
"expected 'module: \"original\"' in the first argument to "
1425+
"@_originallyDefinedIn", ())
1426+
1427+
ERROR(originally_defined_in_need_nonempty_module_name,none,
1428+
"original module name cannot be empty in @_originallyDefinedIn", ())
1429+
1430+
ERROR(originally_defined_in_need_platform_version,none,
1431+
"expected at least one platform version in @_originallyDefinedIn", ())
1432+
1433+
WARNING(originally_defined_in_major_minor_only,none,
1434+
"@_originallyDefinedIn only uses major and minor version number", ())
1435+
1436+
WARNING(originally_defined_in_missing_platform_name,none,
1437+
"* as platform name has no effect", ())
1438+
14131439
// convention
14141440
ERROR(convention_attribute_expected_lparen,none,
14151441
"expected '(' after 'convention' attribute", ())

lib/AST/Attr.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,17 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
682682
Printer << "(\"" << cast<SILGenNameAttr>(this)->Name << "\")";
683683
break;
684684

685+
case DAK_OriginallyDefinedIn: {
686+
Printer.printAttrName("@_originallyDefinedIn");
687+
Printer << "(module: ";
688+
auto Attr = cast<OriginallyDefinedInAttr>(this);
689+
Printer << "\"" << Attr->OriginalModuleName << "\", ";
690+
Printer << platformString(Attr->Platform) << " " <<
691+
Attr->MovedVersion.getAsString();
692+
Printer << ")";
693+
break;
694+
}
695+
685696
case DAK_Available: {
686697
Printer.printAttrName("@available");
687698
Printer << "(";
@@ -989,6 +1000,8 @@ StringRef DeclAttribute::getAttrName() const {
9891000
return "_projectedValueProperty";
9901001
case DAK_Differentiable:
9911002
return "differentiable";
1003+
case DAK_OriginallyDefinedIn:
1004+
return "_originallyDefinedIn";
9921005
}
9931006
llvm_unreachable("bad DeclAttrKind");
9941007
}

lib/Parse/ParseDecl.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,7 +1530,124 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
15301530
/*Implicit=*/false));
15311531
break;
15321532
}
1533+
case DAK_OriginallyDefinedIn: {
1534+
auto LeftLoc = Tok.getLoc();
1535+
if (!consumeIf(tok::l_paren)) {
1536+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
1537+
DeclAttribute::isDeclModifier(DK));
1538+
return false;
1539+
}
1540+
SourceLoc RightLoc;
1541+
enum class NextSegmentKind: uint8_t {
1542+
ModuleName = 0,
1543+
PlatformVersion,
1544+
};
1545+
NextSegmentKind NK = NextSegmentKind::ModuleName;
1546+
StringRef OriginalModuleName;
1547+
llvm::SmallVector<std::pair<PlatformKind, llvm::VersionTuple>, 4>
1548+
PlatformAndVersions;
1549+
1550+
StringRef AttrName = "@_originalDefinedIn";
1551+
if (parseList(tok::r_paren, LeftLoc, RightLoc, false,
1552+
diag::originally_defined_in_missing_rparen,
1553+
SyntaxKind::Unknown, [&]() -> ParserStatus {
1554+
SWIFT_DEFER {
1555+
if (NK != NextSegmentKind::PlatformVersion) {
1556+
NK = (NextSegmentKind)((uint8_t)NK + (uint8_t)1);
1557+
}
1558+
};
1559+
switch (NK) {
1560+
// Parse 'module: "original_module_name"'.
1561+
case NextSegmentKind::ModuleName: {
1562+
// Parse 'module' ':'.
1563+
if (!Tok.is(tok::identifier) || Tok.getText() != "module" ||
1564+
!peekToken().is(tok::colon)) {
1565+
diagnose(Tok, diag::originally_defined_in_need_original_module_name);
1566+
return makeParserError();
1567+
}
1568+
consumeToken(tok::identifier);
1569+
consumeToken(tok::colon);
1570+
// Parse the next string literal as the original module name.
1571+
auto ModuleNameLoc = Tok.getLoc();
1572+
if (Tok.is(tok::string_literal)) {
1573+
auto NameOp = getStringLiteralIfNotInterpolated(Tok.getLoc(),
1574+
"original module name");
1575+
if (NameOp.hasValue())
1576+
OriginalModuleName = *NameOp;
1577+
consumeToken();
1578+
}
1579+
if (OriginalModuleName.empty()) {
1580+
diagnose(ModuleNameLoc,
1581+
diag::originally_defined_in_need_nonempty_module_name);
1582+
return makeParserError();
1583+
}
1584+
return makeParserSuccess();
1585+
}
1586+
// Parse 'OSX 13.13'.
1587+
case NextSegmentKind::PlatformVersion: {
1588+
if ((Tok.is(tok::identifier) || Tok.is(tok::oper_binary_spaced)) &&
1589+
(peekToken().is(tok::floating_literal) ||
1590+
peekToken().is(tok::integer_literal))) {
1591+
PlatformKind Platform;
1592+
// Parse platform name.
1593+
auto Plat = platformFromString(Tok.getText());
1594+
if (!Plat.hasValue()) {
1595+
diagnose(Tok.getLoc(),
1596+
diag::originally_defined_in_unrecognized_platform);
1597+
return makeParserError();
1598+
} else {
1599+
consumeToken();
1600+
Platform = *Plat;
1601+
}
1602+
// Parse version number
1603+
llvm::VersionTuple VerTuple;
1604+
SourceRange VersionRange;
1605+
if (parseVersionTuple(VerTuple, VersionRange,
1606+
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
1607+
return makeParserError();
1608+
} else {
1609+
if (VerTuple.getSubminor().hasValue() ||
1610+
VerTuple.getBuild().hasValue()) {
1611+
diagnose(Tok.getLoc(), diag::originally_defined_in_major_minor_only);
1612+
}
1613+
// * as platform name isn't supported.
1614+
if (Platform == PlatformKind::none) {
1615+
diagnose(AtLoc, diag::originally_defined_in_missing_platform_name);
1616+
} else {
1617+
PlatformAndVersions.emplace_back(Platform, VerTuple);
1618+
}
1619+
return makeParserSuccess();
1620+
}
1621+
}
1622+
diagnose(AtLoc, diag::originally_defined_in_need_platform_version);
1623+
return makeParserError();
1624+
}
1625+
}
1626+
}).isError()) {
1627+
return false;
1628+
}
1629+
if (OriginalModuleName.empty()) {
1630+
diagnose(AtLoc, diag::originally_defined_in_need_nonempty_module_name);
1631+
return false;
1632+
}
1633+
if (PlatformAndVersions.empty()) {
1634+
diagnose(AtLoc, diag::originally_defined_in_need_platform_version);
1635+
return false;
1636+
}
15331637

1638+
assert(!OriginalModuleName.empty());
1639+
assert(!PlatformAndVersions.empty());
1640+
assert(NK == NextSegmentKind::PlatformVersion);
1641+
AttrRange = SourceRange(Loc, Tok.getLoc());
1642+
for (auto &Item: PlatformAndVersions) {
1643+
Attributes.add(new (Context) OriginallyDefinedInAttr(AtLoc, AttrRange,
1644+
OriginalModuleName,
1645+
Item.first,
1646+
Item.second,
1647+
/*IsImplicit*/false));
1648+
}
1649+
break;
1650+
}
15341651
case DAK_Available: {
15351652
if (!consumeIf(tok::l_paren)) {
15361653
diagnose(Loc, diag::attr_expected_lparen, AttrName,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
177177
void visitFinalAttr(FinalAttr *attr);
178178
void visitIBActionAttr(IBActionAttr *attr);
179179
void visitIBSegueActionAttr(IBSegueActionAttr *attr);
180+
void visitOriginallyDefinedInAttr(OriginallyDefinedInAttr *attr);
180181
void visitLazyAttr(LazyAttr *attr);
181182
void visitIBDesignableAttr(IBDesignableAttr *attr);
182183
void visitIBInspectableAttr(IBInspectableAttr *attr);
@@ -408,6 +409,11 @@ void AttributeChecker::visitIBActionAttr(IBActionAttr *attr) {
408409
validateIBActionSignature(Ctx, attr, FD, /*minParams=*/1, /*maxParams=*/1);
409410
}
410411

412+
void
413+
AttributeChecker::visitOriginallyDefinedInAttr(OriginallyDefinedInAttr *attr) {
414+
// TODO: implement diagnostics
415+
}
416+
411417
void AttributeChecker::visitIBSegueActionAttr(IBSegueActionAttr *attr) {
412418
// Only instance methods can be IBActions.
413419
const FuncDecl *FD = cast<FuncDecl>(D);

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ namespace {
13591359
UNINTERESTING_ATTR(DisfavoredOverload)
13601360
UNINTERESTING_ATTR(FunctionBuilder)
13611361
UNINTERESTING_ATTR(ProjectedValueProperty)
1362+
UNINTERESTING_ATTR(OriginallyDefinedIn)
13621363
#undef UNINTERESTING_ATTR
13631364

13641365
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/Deserialization.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,6 +3977,28 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
39773977
Attr = new (ctx) EffectsAttr((EffectsKind)kind);
39783978
break;
39793979
}
3980+
case decls_block::OriginallyDefinedIn_DECL_ATTR: {
3981+
bool isImplicit;
3982+
unsigned Platform;
3983+
DEF_VER_TUPLE_PIECES(MovedVer);
3984+
// Decode the record, pulling the version tuple information.
3985+
serialization::decls_block::OriginallyDefinedInDeclAttrLayout::readRecord(
3986+
scratch,
3987+
isImplicit,
3988+
LIST_VER_TUPLE_PIECES(MovedVer),
3989+
Platform);
3990+
llvm::VersionTuple MovedVer;
3991+
DECODE_VER_TUPLE(MovedVer)
3992+
auto ModuleNameEnd = blobData.find('\0');
3993+
assert(ModuleNameEnd != StringRef::npos);
3994+
auto ModuleName = blobData.slice(0, ModuleNameEnd);
3995+
Attr = new (ctx) OriginallyDefinedInAttr(SourceLoc(), SourceRange(),
3996+
ModuleName,
3997+
(PlatformKind)Platform,
3998+
MovedVer,
3999+
isImplicit);
4000+
break;
4001+
}
39804002

39814003
case decls_block::Available_DECL_ATTR: {
39824004
bool isImplicit;

lib/Serialization/ModuleFormat.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,14 @@ namespace decls_block {
17301730
BCBlob // platform, followed by message
17311731
>;
17321732

1733+
using OriginallyDefinedInDeclAttrLayout = BCRecordLayout<
1734+
OriginallyDefinedIn_DECL_ATTR,
1735+
BCFixed<1>, // implicit flag
1736+
BC_AVAIL_TUPLE, // moved OS version
1737+
BCVBR<5>, // platform
1738+
BCBlob // original module name
1739+
>;
1740+
17331741
using ObjCDeclAttrLayout = BCRecordLayout<
17341742
ObjC_DECL_ATTR,
17351743
BCFixed<1>, // implicit flag

lib/Serialization/Serialization.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,6 +2181,22 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
21812181
return;
21822182
}
21832183

2184+
case DAK_OriginallyDefinedIn: {
2185+
auto *theAttr = cast<OriginallyDefinedInAttr>(DA);
2186+
ENCODE_VER_TUPLE(Moved, llvm::Optional<llvm::VersionTuple>(theAttr->MovedVersion));
2187+
auto abbrCode = S.DeclTypeAbbrCodes[OriginallyDefinedInDeclAttrLayout::Code];
2188+
llvm::SmallString<32> blob;
2189+
blob.append(theAttr->OriginalModuleName.str());
2190+
blob.push_back('\0');
2191+
OriginallyDefinedInDeclAttrLayout::emitRecord(
2192+
S.Out, S.ScratchRecord, abbrCode,
2193+
theAttr->isImplicit(),
2194+
LIST_VER_TUPLE_PIECES(Moved),
2195+
static_cast<unsigned>(theAttr->Platform),
2196+
blob);
2197+
return;
2198+
}
2199+
21842200
case DAK_Available: {
21852201
auto *theAttr = cast<AvailableAttr>(DA);
21862202
ENCODE_VER_TUPLE(Introduced, theAttr->Introduced)

0 commit comments

Comments
 (0)