Skip to content

Commit 9e9c80e

Browse files
jrose-appleslavapestov
authored andcommitted
Add a @_versioned attribute for testing resilience.
This attribute is a stand-in for the versioning annotations described in docs/LibraryEvolution.rst; right now it's just present or absent, and its only effect is to make sure versioned internal decls are treated as public at the SIL level. (This functionality already existed for -enable-testing, so it can probably be trusted.) Also, allow inlineable functions to reference transparent and inline-always functions /if/ they're only called immediately (not used as values or partial-applied), since they'll be inlined away before emitting IR. (We should really only allow this /before/ mandatory inlining, but we don't have a separate SIL stage for that.)
1 parent 37c461c commit 9e9c80e

File tree

7 files changed

+58
-5
lines changed

7 files changed

+58
-5
lines changed

include/swift/AST/Attr.def

+7
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ SIMPLE_DECL_ATTR(_show_in_interface, ShowInInterface,
252252
DECL_ATTR(_cdecl, CDecl,
253253
OnFunc | LongAttribute | UserInaccessible, 63)
254254

255+
// A testing attribute for Library Evolution ("resilience").
256+
// FIXME: Replace with improved @available attribute.
257+
SIMPLE_DECL_ATTR(_versioned, Versioned,
258+
OnFunc | OnVar | OnSubscript | OnConstructor |
259+
OnStruct | OnEnum | OnClass | OnProtocol |
260+
LongAttribute | UserInaccessible,
261+
64)
255262

256263
#undef TYPE_ATTR
257264
#undef DECL_ATTR_ALIAS

include/swift/AST/Decl.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -5810,16 +5810,17 @@ inline bool ValueDecl::isSettable(const DeclContext *UseDC,
58105810
}
58115811

58125812
namespace impl {
5813-
bool isTestingEnabled(const ValueDecl *VD);
5813+
bool isInternalDeclEffectivelyPublic(const ValueDecl *VD);
58145814
}
58155815

58165816
inline Accessibility ValueDecl::getEffectiveAccess() const {
58175817
switch (getFormalAccess()) {
58185818
case Accessibility::Public:
58195819
return Accessibility::Public;
58205820
case Accessibility::Internal:
5821-
if (impl::isTestingEnabled(this))
5821+
if (impl::isInternalDeclEffectivelyPublic(this)) {
58225822
return Accessibility::Public;
5823+
}
58235824
return Accessibility::Internal;
58245825
case Accessibility::Private:
58255826
return Accessibility::Private;

lib/AST/Decl.cpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,21 @@
4343

4444
using namespace swift;
4545

46-
bool impl::isTestingEnabled(const ValueDecl *VD) {
47-
return VD->getModuleContext()->isTestingEnabled();
46+
bool impl::isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
47+
assert(VD->getFormalAccess() == Accessibility::Internal);
48+
49+
if (VD->getAttrs().hasAttribute<VersionedAttr>())
50+
return true;
51+
52+
if (auto *fn = dyn_cast<FuncDecl>(VD))
53+
if (auto *ASD = fn->getAccessorStorageDecl())
54+
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
55+
return true;
56+
57+
if (VD->getModuleContext()->isTestingEnabled())
58+
return true;
59+
60+
return false;
4861
}
4962

5063
clang::SourceLocation ClangNode::getLocation() const {

lib/SIL/SILVerifier.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -931,14 +931,31 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
931931
return isValidLinkageForFragileRef(RefF->getLinkage());
932932
}
933933

934+
/// Returns true if \p FRI is only used as a callee and will always be
935+
/// inlined at those call sites.
936+
static bool isAlwaysInlined(FunctionRefInst *FRI) {
937+
if (FRI->getReferencedFunction()->getInlineStrategy() != AlwaysInline &&
938+
!FRI->getReferencedFunction()->isTransparent()) {
939+
return false;
940+
}
941+
942+
for (auto use : FRI->getUses()) {
943+
auto site = FullApplySite::isa(use->getUser());
944+
if (!site || site.getCallee() != FRI)
945+
return false;
946+
}
947+
return true;
948+
}
949+
934950
void checkFunctionRefInst(FunctionRefInst *FRI) {
935951
auto fnType = requireObjectType(SILFunctionType, FRI,
936952
"result of function_ref");
937953
require(!fnType->getExtInfo().hasContext(),
938954
"function_ref should have a context-free function result");
939955
if (F.isFragile()) {
940956
SILFunction *RefF = FRI->getReferencedFunction();
941-
require(isValidLinkageForFragileRef(RefF),
957+
require(isAlwaysInlined(FRI)
958+
|| isValidLinkageForFragileRef(RefF),
942959
"function_ref inside fragile function cannot "
943960
"reference a private or hidden symbol");
944961
}

lib/Sema/TypeCheckAttr.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
7979
IGNORED_ATTR(Testable)
8080
IGNORED_ATTR(UIApplicationMain)
8181
IGNORED_ATTR(UnsafeNoObjCTaggedPointer)
82+
IGNORED_ATTR(Versioned)
8283
IGNORED_ATTR(WarnUnusedResult)
8384
IGNORED_ATTR(ShowInInterface)
8485
#undef IGNORED_ATTR
@@ -652,6 +653,9 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
652653
IGNORED_ATTR(Testable)
653654
IGNORED_ATTR(WarnUnqualifiedAccess)
654655
IGNORED_ATTR(ShowInInterface)
656+
657+
// FIXME: We actually do have things to enforce for versioned API.
658+
IGNORED_ATTR(Versioned)
655659
#undef IGNORED_ATTR
656660

657661
void visitAvailableAttr(AvailableAttr *attr);

lib/Sema/TypeCheckDecl.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5084,6 +5084,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
50845084
UNINTERESTING_ATTR(Semantics)
50855085
UNINTERESTING_ATTR(SetterAccessibility)
50865086
UNINTERESTING_ATTR(UIApplicationMain)
5087+
UNINTERESTING_ATTR(Versioned)
50875088
UNINTERESTING_ATTR(ObjCNonLazyRealization)
50885089
UNINTERESTING_ATTR(UnsafeNoObjCTaggedPointer)
50895090
UNINTERESTING_ATTR(SwiftNativeObjCRuntimeBase)

test/SILGen/transparent_attribute.swift

+10
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,13 @@ struct testVarDeclShortenedSyntax {
200200
}
201201
zim()
202202
}
203+
204+
205+
// Check that @_versioned entities have public linkage.
206+
// CHECK-LABEL: sil @_TF21transparent_attribute25referencedFromTransparentFT_T_ : $@convention(thin) () -> () {
207+
@_versioned func referencedFromTransparent() {}
208+
209+
// CHECK-LABEL: sil [transparent] [fragile] @_TF21transparent_attribute23referencesVersionedFuncFT_FT_T_ : $@convention(thin) () -> @owned @callee_owned () -> () {
210+
@_transparent public func referencesVersionedFunc() -> () -> () {
211+
return referencedFromTransparent
212+
}

0 commit comments

Comments
 (0)