Skip to content

Commit 5de6fa2

Browse files
committed
[SE-0497] Implement @export attribute syntax
Implement the @export(implementation) and @export(interface) attributes to replace @_alwaysEmitIntoClient and @_neverEmitIntoClient. Provide a warning + Fix-It to start staging out the very-new @_neverEmitIntoClient. We'll hold off on pushing folks toward @_alwaysEmitIntoClient for a little longer.
1 parent ed85a12 commit 5de6fa2

38 files changed

+365
-139
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/AttrKind.h"
2222
#include "swift/AST/DiagnosticKind.h"
2323
#include "swift/AST/DiagnosticList.h"
24+
#include "swift/AST/ExportKind.h"
2425
#include "swift/AST/GenericTypeParamKind.h"
2526
#include "swift/AST/Identifier.h"
2627
#include "swift/AST/LayoutConstraintKind.h"
@@ -956,6 +957,12 @@ BridgedImplementsAttr BridgedImplementsAttr_createParsed(
956957
swift::SourceRange range, BridgedTypeRepr cProtocolType,
957958
BridgedDeclNameRef cMemberName, BridgedDeclNameLoc cMemberNameLoc);
958959

960+
SWIFT_NAME("BridgedExportAttr.createParsed(_:atLoc:range:kind:)")
961+
BridgedExportAttr BridgedExportAttr_createParsed(BridgedASTContext cContext,
962+
swift::SourceLoc atLoc,
963+
swift::SourceRange range,
964+
swift::ExportKind kind);
965+
959966
SWIFT_NAME("BridgedInlineAttr.createParsed(_:atLoc:range:kind:)")
960967
BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext,
961968
swift::SourceLoc atLoc,

include/swift/AST/Attr.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/AvailabilityRange.h"
2424
#include "swift/AST/ConcreteDeclRef.h"
2525
#include "swift/AST/DeclNameLoc.h"
26+
#include "swift/AST/ExportKind.h"
2627
#include "swift/AST/Identifier.h"
2728
#include "swift/AST/KnownProtocols.h"
2829
#include "swift/AST/LifetimeDependence.h"
@@ -2955,6 +2956,35 @@ enum class NonSendableKind : uint8_t {
29552956
Assumed
29562957
};
29572958

2959+
/// Specify whether the declaration should be exported as an interface or
2960+
/// an implementation.
2961+
class ExportAttr : public DeclAttribute {
2962+
public:
2963+
/// How this declaration is exported.
2964+
const ExportKind exportKind;
2965+
2966+
ExportAttr(SourceLoc atLoc, SourceRange range, ExportKind exportKind,
2967+
bool implicit = false)
2968+
: DeclAttribute(DeclAttrKind::Export, atLoc, range, implicit),
2969+
exportKind(exportKind) {}
2970+
2971+
ExportAttr(ExportKind exportKind, bool implicit = false)
2972+
: ExportAttr(SourceLoc(), SourceRange(), exportKind, implicit) { }
2973+
2974+
static bool classof(const DeclAttribute *DA) {
2975+
return DA->getKind() == DeclAttrKind::Export;
2976+
}
2977+
2978+
/// Create a copy of this attribute.
2979+
ExportAttr *clone(ASTContext &ctx) const {
2980+
return new (ctx) ExportAttr(AtLoc, Range, exportKind, isImplicit());
2981+
}
2982+
2983+
bool isEquivalent(const ExportAttr *other, Decl *attachedTo) const {
2984+
return exportKind == other->exportKind;
2985+
}
2986+
};
2987+
29582988
/// Marks a declaration as explicitly non-Sendable.
29592989
class NonSendableAttr : public DeclAttribute {
29602990
public:

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,12 +1085,22 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
10851085
/// behaviors for it and, if it's an extension, its members.
10861086
bool isObjCImplementation() const;
10871087

1088+
/// True if this declaration should always have its implementation made
1089+
/// available to the client, and not have an ABI symbol.
1090+
///
1091+
/// This can be spelled with @export(implementation) or the historical
1092+
/// @_alwaysEmitIntoClient.
1093+
bool isAlwaysEmittedIntoClient() const;
1094+
10881095
/// True if this declaration should never have its implementation made
10891096
/// available to any client. This overrides cross-module optimization and
10901097
/// optimizations that might use the implementation, such that the only
10911098
/// implementation of this function is the one compiled into its owning
10921099
/// module. Practically speaking, this prohibits serialization of the SIL
10931100
/// for this definition.
1101+
///
1102+
/// This can be spelled with @export(interface) or the historical
1103+
/// @_neverEmitIntoClient.
10941104
bool isNeverEmittedIntoClient() const;
10951105

10961106
using AuxiliaryDeclCallback = llvm::function_ref<void(Decl *)>;

include/swift/AST/DeclAttr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,10 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative,
558558
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | ForbiddenInABIAttr,
559559
100)
560560

561-
// Unused '101'
561+
DECL_ATTR(export, Export,
562+
OnVar | OnSubscript | OnAbstractFunction,
563+
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
564+
101)
562565

563566
CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
564567
OnClass,

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4170,6 +4170,10 @@ ERROR(final_not_allowed_here,none,
41704170
"'final' may only be applied to classes, properties, methods, and "
41714171
"subscripts", ())
41724172

4173+
ERROR(attr_incompatible_with_attr,none,
4174+
"'%0' cannot be used with '%1'",
4175+
(DeclAttribute, DeclAttribute))
4176+
41734177
ERROR(attr_incompatible_with_non_final,none,
41744178
"'%0' cannot be applied to a non-final %kindonly1",
41754179
(DeclAttribute, const ValueDecl *))
@@ -5369,7 +5373,7 @@ GROUPED_ERROR(opaque_type_unsupported_availability,OpaqueTypeInference,none,
53695373
"a default argument value|" \
53705374
"a property initializer in a '@frozen' type|" \
53715375
"a '@backDeployed' function|" \
5372-
"an embedded function not marked '@_neverEmitIntoClient'}"
5376+
"an embedded function not marked '@export(interface)'}"
53735377

53745378
ERROR(discard_wrong_context_decl,none,
53755379
"'discard' statement cannot appear in %kindonly0",

include/swift/AST/KnownIdentifiers.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ IDENTIFIER(always)
332332
IDENTIFIER_(_always)
333333
IDENTIFIER_(assumed)
334334
IDENTIFIER(checked)
335+
IDENTIFIER(interface)
336+
IDENTIFIER(implementation)
335337
IDENTIFIER(never)
336338
IDENTIFIER(none)
337339
IDENTIFIER(safe)

include/swift/SIL/SILFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,7 @@ class SILFunction
14211421
return false;
14221422

14231423
auto *V = getLocation().getAsASTNode<ValueDecl>();
1424-
return V && V->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>();
1424+
return V && V->isAlwaysEmittedIntoClient();
14251425
}
14261426

14271427
/// Return whether this function has attribute @used on it

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,7 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const {
17641764
// Exclude decls with @_alwaysEmitIntoClient if we are checking ABI.
17651765
// These decls are considered effectively public because they are usable
17661766
// from inline, so we have to manually exclude them here.
1767-
if (D->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
1767+
if (D->isAlwaysEmittedIntoClient())
17681768
return true;
17691769
} else {
17701770
if (D->isPrivateSystemDecl(false))

lib/AST/ASTDumper.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,15 @@ static StringRef getDumpString(InlineKind kind) {
590590
}
591591
llvm_unreachable("unhandled InlineKind");
592592
}
593+
static StringRef getDumpString(ExportKind kind) {
594+
switch (kind) {
595+
case ExportKind::Interface:
596+
return "interface";
597+
case ExportKind::Implementation:
598+
return "implementation";
599+
}
600+
llvm_unreachable("unhandled ExportKind");
601+
}
593602
static StringRef getDumpString(MacroRole role) {
594603
return getMacroRoleString(role);
595604
}
@@ -5306,6 +5315,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
53065315
printField(Attr->getKind(), Label::always("kind"));
53075316
printFoot();
53085317
}
5318+
void visitExportAttr(ExportAttr *Attr, Label label) {
5319+
printCommon(Attr, "export_attr", label);
5320+
printField(Attr->exportKind, Label::always("kind"));
5321+
printFoot();
5322+
}
53095323
void visitLifetimeAttr(LifetimeAttr *Attr, Label label) {
53105324
printCommon(Attr, "lifetime_attr", label);
53115325
// FIXME: Improve, more detailed info.

lib/AST/Attr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
11291129
case DeclAttrKind::AccessControl:
11301130
case DeclAttrKind::ReferenceOwnership:
11311131
case DeclAttrKind::Effects:
1132+
case DeclAttrKind::Export:
11321133
case DeclAttrKind::Optimize:
11331134
case DeclAttrKind::Exclusivity:
11341135
case DeclAttrKind::NonSendable:
@@ -1932,6 +1933,15 @@ StringRef DeclAttribute::getAttrName() const {
19321933
case EffectsKind::Custom:
19331934
return "_effects";
19341935
}
1936+
case DeclAttrKind::Export: {
1937+
switch (cast<ExportAttr>(this)->exportKind) {
1938+
case ExportKind::Interface:
1939+
return "export(interface)";
1940+
case ExportKind::Implementation:
1941+
return "export(implementation)";
1942+
}
1943+
llvm_unreachable("Invalid export kind");
1944+
}
19351945
case DeclAttrKind::AccessControl:
19361946
case DeclAttrKind::SetterAccess: {
19371947
AccessLevel access = cast<AbstractAccessControlAttr>(this)->getAccess();

0 commit comments

Comments
 (0)