Skip to content

Commit 7f4e5a5

Browse files
authored
Merge pull request #29197 from slavapestov/misc-silgen-fixes
A couple of small SILGen fixes
2 parents 5e0226f + b9f4e12 commit 7f4e5a5

File tree

5 files changed

+66
-28
lines changed

5 files changed

+66
-28
lines changed

lib/SIL/SILDeclRef.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -958,67 +958,94 @@ SubclassScope SILDeclRef::getSubclassScope() const {
958958
if (!isa<AbstractFunctionDecl>(decl))
959959
return SubclassScope::NotApplicable;
960960

961-
// If this declaration is a function which goes into a vtable, then it's
962-
// symbol must be as visible as its class, because derived classes have to put
963-
// all less visible methods of the base class into their vtables.
961+
DeclContext *context = decl->getDeclContext();
962+
963+
// Only methods in non-final classes go in the vtable.
964+
auto *classType = dyn_cast<ClassDecl>(context);
965+
if (!classType || classType->isFinal())
966+
return SubclassScope::NotApplicable;
967+
968+
// If a method appears in the vtable of a class, we must give it's symbol
969+
// special consideration when computing visibility because the SIL-level
970+
// linkage does not map to the symbol's visibility in a straightforward
971+
// way.
972+
//
973+
// In particular, the rules are:
974+
// - If the class metadata is not resilient, then all method symbols must
975+
// be visible from any translation unit where a subclass might be defined,
976+
// because the subclass metadata will re-emit all vtable entries.
977+
//
978+
// - For resilient classes, we do the opposite: generally, a method's symbol
979+
// can be hidden from other translation units, because we want to enforce
980+
// that resilient access patterns are used for method calls and overrides.
981+
//
982+
// Constructors and final methods are the exception here, because they can
983+
// be called directly.
984+
985+
// FIXME: This is too narrow. Any class with resilient metadata should
986+
// probably have this, at least for method overrides that don't add new
987+
// vtable entries.
988+
bool isResilientClass = classType->isResilient();
964989

965990
if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
991+
if (isResilientClass)
992+
return SubclassScope::NotApplicable;
966993
// Initializing entry points do not appear in the vtable.
967994
if (kind == SILDeclRef::Kind::Initializer)
968995
return SubclassScope::NotApplicable;
969-
// Non-required convenience inits do not apper in the vtable.
996+
// Non-required convenience inits do not appear in the vtable.
970997
if (!CD->isRequired() && !CD->isDesignatedInit())
971998
return SubclassScope::NotApplicable;
972999
} else if (isa<DestructorDecl>(decl)) {
973-
// Detructors do not appear in the vtable.
1000+
// Destructors do not appear in the vtable.
9741001
return SubclassScope::NotApplicable;
9751002
} else {
9761003
assert(isa<FuncDecl>(decl));
9771004
}
9781005

979-
DeclContext *context = decl->getDeclContext();
980-
981-
// Methods from extensions don't go in the vtable.
982-
if (isa<ExtensionDecl>(context))
983-
return SubclassScope::NotApplicable;
984-
985-
// Various forms of thunks don't either.
1006+
// Various forms of thunks don't go in the vtable.
9861007
if (isThunk() || isForeign)
9871008
return SubclassScope::NotApplicable;
9881009

9891010
// Default arg generators don't go in the vtable.
9901011
if (isDefaultArgGenerator())
9911012
return SubclassScope::NotApplicable;
9921013

993-
// Only methods in non-final classes go in the vtable.
994-
auto *classType = context->getSelfClassDecl();
995-
if (!classType || classType->isFinal())
996-
return SubclassScope::NotApplicable;
1014+
if (decl->isFinal()) {
1015+
// Final methods only go in the vtable if they override something.
1016+
if (!decl->getOverriddenDecl())
1017+
return SubclassScope::NotApplicable;
9971018

998-
// Final methods only go in the vtable if they override something.
999-
if (decl->isFinal() && !decl->getOverriddenDecl())
1000-
return SubclassScope::NotApplicable;
1019+
// In the resilient case, we're going to be making symbols _less_
1020+
// visible, so make sure we stop now; final methods can always be
1021+
// called directly.
1022+
if (isResilientClass)
1023+
return SubclassScope::Internal;
1024+
}
10011025

10021026
assert(decl->getEffectiveAccess() <= classType->getEffectiveAccess() &&
10031027
"class must be as visible as its members");
10041028

1005-
// FIXME: This is too narrow. Any class with resilient metadata should
1006-
// probably have this, at least for method overrides that don't add new
1007-
// vtable entries.
1008-
if (classType->isResilient()) {
1009-
if (isa<ConstructorDecl>(decl))
1010-
return SubclassScope::NotApplicable;
1029+
if (isResilientClass) {
1030+
// The symbol should _only_ be reached via the vtable, so we're
1031+
// going to make it hidden.
10111032
return SubclassScope::Resilient;
10121033
}
10131034

10141035
switch (classType->getEffectiveAccess()) {
10151036
case AccessLevel::Private:
10161037
case AccessLevel::FilePrivate:
1038+
// If the class is private, it can only be subclassed from the same
1039+
// SILModule, so we don't need to do anything.
10171040
return SubclassScope::NotApplicable;
10181041
case AccessLevel::Internal:
10191042
case AccessLevel::Public:
1043+
// If the class is internal or public, it can only be subclassed from
1044+
// the same AST Module, but possibly a different SILModule.
10201045
return SubclassScope::Internal;
10211046
case AccessLevel::Open:
1047+
// If the class is open, it can be subclassed from a different
1048+
// AST Module. All method symbols are public.
10221049
return SubclassScope::External;
10231050
}
10241051

lib/SILGen/SILGenBridging.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &SGF,
730730
nativeType);
731731

732732
// Put the value into memory if necessary.
733-
assert(v.getType().isTrivial(SGF.F) || v.hasCleanup());
733+
assert(v.getOwnershipKind() == ValueOwnershipKind::None || v.hasCleanup());
734734
SILModuleConventions silConv(SGF.SGM.M);
735735
// bridgeAnything always takes an indirect argument as @in.
736736
// Since we don't have the SIL type here, check the current SIL stage/mode

lib/SILGen/SILGenBuilder.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,7 @@ ManagedValue SILGenBuilder::createStore(SILLocation loc, ManagedValue value,
669669
SILValue address,
670670
StoreOwnershipQualifier qualifier) {
671671
CleanupCloner cloner(*this, value);
672-
if (value.getType().isTrivial(SGF.F) ||
673-
value.getOwnershipKind() == ValueOwnershipKind::None)
672+
if (value.getOwnershipKind() == ValueOwnershipKind::None)
674673
qualifier = StoreOwnershipQualifier::Trivial;
675674
createStore(loc, value.forward(SGF), address, qualifier);
676675
return cloner.clone(address);

test/IRGen/method_linkage.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ open class OpenSubclass : OpenClass {
118118
fileprivate final override var prop: () {
119119
return ()
120120
}
121+
122+
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$s14method_linkage12OpenSubclassC4pbazyyF"
123+
// RESILIENT: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$s14method_linkage12OpenSubclassC4pbazyyF"
124+
public final override func pbaz() {}
121125
}
122126

123127
// Just in case anyone wants to delete unused methods...

test/SILGen/objc_bridging_any.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,15 @@ class SwiftAnyEnjoyer: NSIdLover, NSIdLoving {
690690
func takesId(viaProtocol x: Any) { }
691691
}
692692

693+
enum SillyOptional {
694+
case nothing
695+
case something(NSObject)
696+
}
693697

698+
func bridgeNoPayloadEnumCase(_ receiver: NSIdLover) {
699+
let value = SillyOptional.nothing
700+
receiver.takesId(value)
701+
}
694702

695703
// CHECK-LABEL: sil_witness_table shared [serialized] GenericOption: Hashable module objc_generics {
696704
// CHECK-NEXT: base_protocol Equatable: GenericOption: Equatable module objc_generics

0 commit comments

Comments
 (0)