Skip to content

Commit 5a862e4

Browse files
authored
Merge pull request swiftlang#28369 from nkcsgexi/originally-defined-in-attribute
AST: introduce a new attribute @_originallyDefinedIn to the AST
2 parents fdec50a + aa1e4ee commit 5a862e4

File tree

13 files changed

+324
-2
lines changed

13 files changed

+324
-2
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,12 @@ SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction,
523523
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
524524
95)
525525

526+
DECL_ATTR(_originallyDefinedIn, OriginallyDefinedIn,
527+
OnNominalType | OnFunc | OnVar | OnExtension | UserInaccessible |
528+
AllowMultipleAttributes |
529+
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
530+
96)
531+
526532
#undef TYPE_ATTR
527533
#undef DECL_ATTR_ALIAS
528534
#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
@@ -1397,6 +1397,32 @@ WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
13971397
"unexpected version number in '%0' attribute for non-specific platform "
13981398
"'*'", (StringRef))
13991399

1400+
// originallyDefinedIn
1401+
ERROR(originally_defined_in_missing_rparen,none,
1402+
"expected ')' in @_originallyDefinedIn argument list", ())
1403+
1404+
ERROR(originally_defined_in_unrecognized_platform,none,
1405+
"unrecognized platform name in @_originallyDefinedIn argument list", ())
1406+
1407+
ERROR(originally_defined_in_unrecognized_property,none,
1408+
"unrecognized property in @_originallyDefinedIn argument list", ())
1409+
1410+
ERROR(originally_defined_in_need_original_module_name,none,
1411+
"expected 'module: \"original\"' in the first argument to "
1412+
"@_originallyDefinedIn", ())
1413+
1414+
ERROR(originally_defined_in_need_nonempty_module_name,none,
1415+
"original module name cannot be empty in @_originallyDefinedIn", ())
1416+
1417+
ERROR(originally_defined_in_need_platform_version,none,
1418+
"expected at least one platform version in @_originallyDefinedIn", ())
1419+
1420+
WARNING(originally_defined_in_major_minor_only,none,
1421+
"@_originallyDefinedIn only uses major and minor version number", ())
1422+
1423+
WARNING(originally_defined_in_missing_platform_name,none,
1424+
"* as platform name has no effect", ())
1425+
14001426
// convention
14011427
ERROR(convention_attribute_expected_lparen,none,
14021428
"expected '(' after 'convention' attribute", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,9 @@ WARNING(option_set_zero_constant,none,
14611461
NOTE(option_set_empty_set_init,none,
14621462
"use [] to silence this warning", ())
14631463

1464+
ERROR(originally_defined_in_dupe_platform,none,
1465+
"duplicate version number for platform %0", (StringRef))
1466+
14641467
// Alignment attribute
14651468
ERROR(alignment_not_power_of_two,none,
14661469
"alignment value must be a power of two", ())

lib/AST/Attr.cpp

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

694+
case DAK_OriginallyDefinedIn: {
695+
Printer.printAttrName("@_originallyDefinedIn");
696+
Printer << "(module: ";
697+
auto Attr = cast<OriginallyDefinedInAttr>(this);
698+
Printer << "\"" << Attr->OriginalModuleName << "\", ";
699+
Printer << platformString(Attr->Platform) << " " <<
700+
Attr->MovedVersion.getAsString();
701+
Printer << ")";
702+
break;
703+
}
704+
694705
case DAK_Available: {
695706
Printer.printAttrName("@available");
696707
Printer << "(";
@@ -1005,6 +1016,8 @@ StringRef DeclAttribute::getAttrName() const {
10051016
return "_projectedValueProperty";
10061017
case DAK_Differentiable:
10071018
return "differentiable";
1019+
case DAK_OriginallyDefinedIn:
1020+
return "_originallyDefinedIn";
10081021
}
10091022
llvm_unreachable("bad DeclAttrKind");
10101023
}

lib/Parse/ParseDecl.cpp

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

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

lib/Sema/TypeCheckAttr.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
113113
IGNORED_ATTR(DisfavoredOverload)
114114
IGNORED_ATTR(ProjectedValueProperty)
115115
IGNORED_ATTR(ReferenceOwnership)
116+
IGNORED_ATTR(OriginallyDefinedIn)
116117

117118
// TODO(TF-828): Upstream `@differentiable` attribute type-checking from
118119
// tensorflow branch.
@@ -248,6 +249,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
248249

249250
void visitImplementationOnlyAttr(ImplementationOnlyAttr *attr);
250251
void visitNonEphemeralAttr(NonEphemeralAttr *attr);
252+
void checkOriginalDefinedInAttrs(ArrayRef<OriginallyDefinedInAttr*> Attrs);
251253
};
252254
} // end anonymous namespace
253255

@@ -1014,14 +1016,21 @@ void AttributeChecker::visitOptionalAttr(OptionalAttr *attr) {
10141016

10151017
void TypeChecker::checkDeclAttributes(Decl *D) {
10161018
AttributeChecker Checker(D);
1019+
// We need to check all OriginallyDefinedInAttr relative to each other, so
1020+
// collect them and check in batch later.
1021+
llvm::SmallVector<OriginallyDefinedInAttr*, 4> ODIAttrs;
10171022
for (auto attr : D->getAttrs()) {
10181023
if (!attr->isValid()) continue;
10191024

10201025
// If Attr.def says that the attribute cannot appear on this kind of
10211026
// declaration, diagnose it and disable it.
10221027
if (attr->canAppearOnDecl(D)) {
1023-
// Otherwise, check it.
1024-
Checker.visit(attr);
1028+
if (auto *ODI = dyn_cast<OriginallyDefinedInAttr>(attr)) {
1029+
ODIAttrs.push_back(ODI);
1030+
} else {
1031+
// Otherwise, check it.
1032+
Checker.visit(attr);
1033+
}
10251034
continue;
10261035
}
10271036

@@ -1058,6 +1067,7 @@ void TypeChecker::checkDeclAttributes(Decl *D) {
10581067
else
10591068
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_attribute, attr);
10601069
}
1070+
Checker.checkOriginalDefinedInAttrs(ODIAttrs);
10611071
}
10621072

10631073
/// Returns true if the given method is an valid implementation of a
@@ -2687,6 +2697,23 @@ void TypeChecker::checkParameterAttributes(ParameterList *params) {
26872697
}
26882698
}
26892699

2700+
void
2701+
AttributeChecker::checkOriginalDefinedInAttrs(
2702+
ArrayRef<OriginallyDefinedInAttr*> Attrs) {
2703+
llvm::SmallSet<PlatformKind, 4> AllPlatforms;
2704+
// Attrs are in the reverse order of the source order. We need to visit them
2705+
// in source order to diagnose the later attribute.
2706+
for (auto It = Attrs.rbegin(), End = Attrs.rend(); It != End; ++ It) {
2707+
auto *Attr = *It;
2708+
auto CurPlat = Attr->Platform;
2709+
if (!AllPlatforms.insert(CurPlat).second) {
2710+
// Only one version number is allowed for one platform name.
2711+
diagnose(Attr->AtLoc, diag::originally_defined_in_dupe_platform,
2712+
platformString(Attr->Platform));
2713+
}
2714+
}
2715+
}
2716+
26902717
Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
26912718
ReferenceOwnershipAttr *attr) {
26922719
auto &Diags = var->getASTContext().Diags;

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ namespace {
13611361
UNINTERESTING_ATTR(DisfavoredOverload)
13621362
UNINTERESTING_ATTR(FunctionBuilder)
13631363
UNINTERESTING_ATTR(ProjectedValueProperty)
1364+
UNINTERESTING_ATTR(OriginallyDefinedIn)
13641365
#undef UNINTERESTING_ATTR
13651366

13661367
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

0 commit comments

Comments
 (0)