Skip to content

Commit 60e3373

Browse files
authored
Merge pull request swiftlang#20987 from slavapestov/backward-deployment
Backward deployment fixes and tests
2 parents 5fca3a8 + f5b448f commit 60e3373

22 files changed

+594
-19
lines changed

include/swift/ABI/Metadata.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -845,13 +845,15 @@ struct TargetVTableDescriptorHeader {
845845
template <typename Runtime>
846846
struct TargetMethodOverrideDescriptor {
847847
/// The class containing the base method.
848-
TargetRelativeIndirectablePointer<Runtime, TargetClassDescriptor<Runtime>> Class;
848+
TargetRelativeIndirectablePointer<Runtime, TargetClassDescriptor<Runtime>,
849+
/*nullable*/ true> Class;
849850

850851
/// The base method.
851-
TargetRelativeIndirectablePointer<Runtime, TargetMethodDescriptor<Runtime>> Method;
852+
TargetRelativeIndirectablePointer<Runtime, TargetMethodDescriptor<Runtime>,
853+
/*nullable*/ true> Method;
852854

853855
/// The implementation of the override.
854-
TargetRelativeDirectPointer<Runtime, void, /*Nullable=*/true> Impl;
856+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> Impl;
855857
};
856858

857859
/// Header for a class vtable override descriptor. This is a variable-sized

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ DECL_ATTR(_clangImporterSynthesizedType, ClangImporterSynthesizedType,
362362
NotSerialized, 74)
363363
SIMPLE_DECL_ATTR(_weakLinked, WeakLinked,
364364
OnNominalType | OnAssociatedType | OnFunc | OnAccessor | OnVar |
365-
OnSubscript | OnConstructor | OnEnumElement | UserInaccessible,
365+
OnSubscript | OnConstructor | OnEnumElement | OnExtension | UserInaccessible,
366366
75)
367367
SIMPLE_DECL_ATTR(_frozen, Frozen,
368368
OnEnum |

include/swift/AST/ProtocolConformance.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ class RootProtocolConformance : public ProtocolConformance {
356356

357357
bool isInvalid() const;
358358

359+
/// Whether this conformance is weak-imported.
360+
bool isWeakImported(ModuleDecl *fromModule) const;
361+
359362
bool hasWitness(ValueDecl *requirement) const;
360363
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;
361364

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,12 @@ bool Decl::isWeakImported(ModuleDecl *fromModule) const {
557557
if (auto *dtor = dyn_cast<DestructorDecl>(this))
558558
return cast<ClassDecl>(dtor->getDeclContext())->isWeakImported(fromModule);
559559

560+
auto *dc = getDeclContext();
561+
if (auto *ext = dyn_cast<ExtensionDecl>(dc))
562+
return ext->isWeakImported(fromModule);
563+
if (auto *ntd = dyn_cast<NominalTypeDecl>(dc))
564+
return ntd->isWeakImported(fromModule);
565+
560566
// FIXME: Also check availability when containingModule is resilient.
561567
return false;
562568
}

lib/AST/ProtocolConformance.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,29 @@ SourceLoc RootProtocolConformance::getLoc() const {
394394
ROOT_CONFORMANCE_SUBCLASS_DISPATCH(getLoc, ())
395395
}
396396

397+
bool RootProtocolConformance::isWeakImported(ModuleDecl *fromModule) const {
398+
auto *dc = getDeclContext();
399+
if (dc->getParentModule() == fromModule)
400+
return false;
401+
402+
// If the protocol is weak imported, so are any conformances to it.
403+
if (getProtocol()->isWeakImported(fromModule))
404+
return true;
405+
406+
// If the conforming type is weak imported, so are any of its conformances.
407+
if (auto *nominal = getType()->getAnyNominal())
408+
if (nominal->isWeakImported(fromModule))
409+
return true;
410+
411+
// If the conformance is declared in an extension with the @_weakLinked
412+
// attribute, it is weak imported.
413+
if (auto *ext = dyn_cast<ExtensionDecl>(dc))
414+
if (ext->isWeakImported(fromModule))
415+
return true;
416+
417+
return false;
418+
}
419+
397420
bool RootProtocolConformance::hasWitness(ValueDecl *requirement) const {
398421
ROOT_CONFORMANCE_SUBCLASS_DISPATCH(hasWitness, (requirement))
399422
}

lib/IRGen/Linking.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,11 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
917917
case Kind::DynamicallyReplaceableFunctionImpl:
918918
return getDecl()->isWeakImported(module);
919919

920+
case Kind::ProtocolWitnessTable:
921+
case Kind::ProtocolConformanceDescriptor:
922+
return getProtocolConformance()->getRootConformance()
923+
->isWeakImported(module);
924+
920925
// TODO: Revisit some of the below, for weak conformances.
921926
case Kind::TypeMetadataPattern:
922927
case Kind::TypeMetadataInstantiationCache:
@@ -925,12 +930,10 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
925930
case Kind::TypeMetadataCompletionFunction:
926931
case Kind::ExtensionDescriptor:
927932
case Kind::AnonymousDescriptor:
928-
case Kind::ProtocolWitnessTable:
929933
case Kind::ProtocolWitnessTablePattern:
930934
case Kind::GenericProtocolWitnessTableInstantiationFunction:
931935
case Kind::AssociatedTypeWitnessTableAccessFunction:
932936
case Kind::ReflectionAssociatedTypeDescriptor:
933-
case Kind::ProtocolConformanceDescriptor:
934937
case Kind::ProtocolWitnessTableLazyAccessFunction:
935938
case Kind::ProtocolWitnessTableLazyCacheVariable:
936939
case Kind::ValueWitness:

stdlib/public/runtime/Metadata.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,11 @@ static void initClassVTable(ClassMetadata *self) {
23642364
auto *baseClass = descriptor.Class.get();
23652365
auto *baseMethod = descriptor.Method.get();
23662366

2367+
// If the base method is null, it's an unavailable weak-linked
2368+
// symbol.
2369+
if (baseClass == nullptr || baseMethod == nullptr)
2370+
continue;
2371+
23672372
// Calculate the base method's vtable offset from the
23682373
// base method descriptor. The offset will be relative
23692374
// to the base class's vtable start offset.

test/IRGen/Inputs/weak_import_native_helper.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ public protocol P {
8383
}
8484

8585
@_weakLinked
86-
public struct WeakS {}
86+
public struct WeakS {
87+
public init() {}
88+
public func weakMember() {}
89+
}
8790

8891
@_weakLinked
8992
public enum WeakE {}
@@ -115,3 +118,6 @@ public protocol ProtocolWithWeakMembers {
115118
extension ProtocolWithWeakMembers {
116119
@_weakLinked public func f() {}
117120
}
121+
122+
public protocol BaseP {}
123+
@_weakLinked extension S : BaseP {}

test/IRGen/weak_import_native.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ func testStruct() {
5555
let z = s[0]
5656
s[0] = z
5757
s[0] += 1
58+
59+
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper5WeakSV0A6MemberyyF"
60+
let w = WeakS()
61+
w.weakMember()
5862
}
5963

6064
func testEnum() {
@@ -166,3 +170,8 @@ class WeakGenericSub: GenericC<Int> {
166170
// CHECK-DAG: declare extern_weak swiftcc {{.+}} @"$s25weak_import_native_helper8GenericCCfd"
167171
}
168172
}
173+
174+
protocol RefinesP : BaseP {}
175+
176+
// CHECK-DAG: @"$s25weak_import_native_helper1SVAA5BasePAAWP" = extern_weak global i8*
177+
extension S : RefinesP {}

utils/rth

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class ResilienceTest(object):
3434
def __init__(self, target_build_swift, target_run, target_codesign,
3535
target_nm, tmp_dir, test_dir, test_src, lib_prefix,
3636
lib_suffix, additional_compile_flags,
37-
no_backward_deployment, no_symbol_diff):
37+
backward_deployment, no_symbol_diff):
3838
self.target_build_swift = shlex.split(target_build_swift)
3939
self.target_run = shlex.split(target_run)
4040
self.target_codesign = shlex.split(target_codesign)
@@ -55,7 +55,7 @@ class ResilienceTest(object):
5555
self.lib_name = self.lib_src_name[:-6]
5656
self.lib_src = os.path.join(self.test_dir, 'Inputs', self.lib_src_name)
5757

58-
self.no_backward_deployment = no_backward_deployment
58+
self.backward_deployment = backward_deployment
5959
self.no_symbol_diff = no_symbol_diff
6060

6161
def run(self):
@@ -138,6 +138,12 @@ class ResilienceTest(object):
138138

139139
def compile_main(self):
140140
for config in self.config_dir_map:
141+
# If we're testing backward deployment, we only want to build
142+
# the app against the new version of the library.
143+
if self.backward_deployment and \
144+
config == "BEFORE":
145+
continue
146+
141147
output_obj = os.path.join(self.config_dir_map[config], 'main.o')
142148
compiler_flags = ['-D', config, '-c', self.test_src,
143149
'-Xfrontend', '-enable-class-resilience',
@@ -153,11 +159,8 @@ class ResilienceTest(object):
153159
def configs(self):
154160
for config1 in self.config_dir_map:
155161
for config2 in self.config_dir_map:
156-
# --no-backward-deployment skips testing a new application
157-
# linked against an old library.
158-
if config1 == "BEFORE" and \
159-
config2 == "AFTER" and \
160-
self.no_backward_deployment:
162+
if self.backward_deployment and \
163+
config2 == "BEFORE":
161164
continue
162165

163166
yield (config1, config2)
@@ -185,6 +188,9 @@ class ResilienceTest(object):
185188
'-o', output_obj
186189
]
187190

191+
if self.is_apple_platform():
192+
compiler_flags += ['-Xlinker', '-bind_at_load']
193+
188194
command = self.target_build_swift + compiler_flags
189195
verbose_print_command(command)
190196
returncode = subprocess.call(command)
@@ -221,7 +227,7 @@ def main():
221227
parser.add_argument('--lib-prefix', required=True)
222228
parser.add_argument('--lib-suffix', required=True)
223229
parser.add_argument('--additional-compile-flags', default='')
224-
parser.add_argument('--no-backward-deployment', default=False,
230+
parser.add_argument('--backward-deployment', default=False,
225231
action='store_true')
226232
parser.add_argument('--no-symbol-diff', default=False,
227233
action='store_true')
@@ -233,7 +239,7 @@ def main():
233239
args.t, args.S, args.s, args.lib_prefix,
234240
args.lib_suffix,
235241
args.additional_compile_flags,
236-
args.no_backward_deployment,
242+
args.backward_deployment,
237243
args.no_symbol_diff)
238244

239245
return resilience_test.run()

0 commit comments

Comments
 (0)