Skip to content

Commit 7015543

Browse files
committed
[Module interfaces] More aggressively #if-out declarations.
Extend the checks for marker protocols and rethrows protocols to ensure that we #if out more code that relies on them in module interface generation. This makes the _Concurrency module parseable by much older compilers. Fixes rdar://75291705.
1 parent f1218fc commit 7015543

File tree

3 files changed

+96
-20
lines changed

3 files changed

+96
-20
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,16 +2446,53 @@ static bool usesFeatureAsyncAwait(Decl *decl) {
24462446
}
24472447

24482448
static bool usesFeatureMarkerProtocol(Decl *decl) {
2449+
// Check an inheritance clause for a marker protocol.
2450+
auto checkInherited = [&](ArrayRef<TypeLoc> inherited) -> bool {
2451+
for (const auto &inheritedEntry : inherited) {
2452+
if (auto inheritedType = inheritedEntry.getType()) {
2453+
if (inheritedType->isExistentialType()) {
2454+
auto layout = inheritedType->getExistentialLayout();
2455+
for (ProtocolType *protoTy : layout.getProtocols()) {
2456+
if (protoTy->getDecl()->isMarkerProtocol())
2457+
return true;
2458+
}
2459+
}
2460+
}
2461+
}
2462+
2463+
return false;
2464+
};
2465+
2466+
// Check generic requirements for a marker protocol.
2467+
auto checkRequirements = [&](ArrayRef<Requirement> requirements) -> bool {
2468+
for (const auto &req: requirements) {
2469+
if (req.getKind() == RequirementKind::Conformance &&
2470+
req.getSecondType()->castTo<ProtocolType>()->getDecl()
2471+
->isMarkerProtocol())
2472+
return true;
2473+
}
2474+
2475+
return false;
2476+
};
2477+
24492478
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
24502479
if (proto->isMarkerProtocol())
24512480
return true;
2481+
2482+
if (checkInherited(proto->getInherited()))
2483+
return true;
2484+
2485+
if (checkRequirements(proto->getRequirementSignature()))
2486+
return true;
24522487
}
24532488

24542489
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2455-
if (auto proto = ext->getSelfProtocolDecl())
2456-
if (proto->isMarkerProtocol())
2457-
return true;
2458-
}
2490+
if (checkRequirements(ext->getGenericRequirements()))
2491+
return true;
2492+
2493+
if (checkInherited(ext->getInherited()))
2494+
return true;
2495+
}
24592496

24602497
return false;
24612498
}
@@ -2524,15 +2561,40 @@ static bool usesFeatureRethrowsProtocol(
25242561
if (!checked.insert(decl).second)
25252562
return false;
25262563

2564+
// Check an inheritance clause for a marker protocol.
2565+
auto checkInherited = [&](ArrayRef<TypeLoc> inherited) -> bool {
2566+
for (const auto &inheritedEntry : inherited) {
2567+
if (auto inheritedType = inheritedEntry.getType()) {
2568+
if (inheritedType->isExistentialType()) {
2569+
auto layout = inheritedType->getExistentialLayout();
2570+
for (ProtocolType *protoTy : layout.getProtocols()) {
2571+
if (usesFeatureRethrowsProtocol(protoTy->getDecl(), checked))
2572+
return true;
2573+
}
2574+
}
2575+
}
2576+
}
2577+
2578+
return false;
2579+
};
2580+
2581+
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
2582+
if (checkInherited(nominal->getInherited()))
2583+
return true;
2584+
}
2585+
25272586
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
25282587
if (proto->getAttrs().hasAttribute<AtRethrowsAttr>())
25292588
return true;
25302589
}
25312590

25322591
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2533-
if (auto proto = ext->getSelfProtocolDecl())
2534-
if (usesFeatureRethrowsProtocol(proto, checked))
2592+
if (auto nominal = ext->getSelfNominalTypeDecl())
2593+
if (usesFeatureRethrowsProtocol(nominal, checked))
25352594
return true;
2595+
2596+
if (checkInherited(ext->getInherited()))
2597+
return true;
25362598
}
25372599

25382600
if (auto genericSig = decl->getInnermostDeclContext()

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,11 @@ class InheritedProtocolCollector {
550550
if (!handledProtocols.insert(inherited).second)
551551
return TypeWalker::Action::SkipChildren;
552552

553-
// If 'nominal' is an 'actor class', we do not synthesize its
554-
// conformance to the Actor protocol through a dummy extension.
553+
// If 'nominal' is an actor, we do not synthesize its conformance
554+
// to the Actor protocol through a dummy extension.
555555
// There is a special restriction on the Actor protocol in that
556-
// it is only valid to conform to Actor on an 'actor class' decl,
557-
// not extensions of that 'actor class'.
556+
// it is only valid to conform to Actor on an 'actor' decl,
557+
// not extensions of that 'actor'.
558558
if (actorClass &&
559559
inherited->isSpecificProtocol(KnownProtocolKind::Actor))
560560
return TypeWalker::Action::SkipChildren;

test/ModuleInterface/features.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
// compilers to skip over the uses of newer features.
1111

1212
// CHECK: #if compiler(>=5.3) && $Actors
13-
// CHECK-NEXT: actor {{.*}} MyActor
13+
// CHECK-NEXT: public actor MyActor
1414
// CHECK: }
1515
// CHECK-NEXT: #endif
16-
public actor class MyActor {
16+
public actor MyActor {
1717
}
1818

1919
// CHECK: #if compiler(>=5.3) && $Actors
@@ -47,10 +47,10 @@ public func globalAsync() async { }
4747
// CHECK-NEXT: #endif
4848
@_marker public protocol MP2: MP { }
4949

50-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
51-
// CHECK: public protocol MP3 : FeatureTest.MP {
50+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
51+
// CHECK-NEXT: public protocol MP3 : AnyObject, FeatureTest.MP {
5252
// CHECK-NEXT: }
53-
public protocol MP3: MP { }
53+
public protocol MP3: AnyObject, MP { }
5454

5555
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
5656
// CHECK-NEXT: extension MP2 {
@@ -67,6 +67,14 @@ public class OldSchool: MP {
6767
public func takeClass() async { }
6868
}
6969

70+
// CHECK: class OldSchool2 {
71+
public class OldSchool2: MP {
72+
// CHECK: #if compiler(>=5.3) && $AsyncAwait
73+
// CHECK-NEXT: takeClass()
74+
// CHECK-NEXT: #endif
75+
public func takeClass() async { }
76+
}
77+
7078
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
7179
// CHECK-NEXT: @rethrows public protocol RP
7280
@rethrows public protocol RP {
@@ -84,17 +92,23 @@ public struct UsesRP {
8492
}
8593
}
8694

95+
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
96+
// CHECK-NEXT: public struct IsRP
97+
public struct IsRP: RP {
98+
public func f() { }
99+
}
100+
87101
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
88102
// CHECK-NEXT: public func acceptsRP
89103
public func acceptsRP<T: RP>(_: T) { }
90104

91-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
92-
// CHECK: extension Array : FeatureTest.MP where Element : FeatureTest.MP {
105+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
106+
// CHECK-NEXT: extension Array : FeatureTest.MP where Element : FeatureTest.MP {
93107
extension Array: FeatureTest.MP where Element : FeatureTest.MP { }
94-
// CHECK-NEXT: }
108+
// CHECK: }
95109

96-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
97-
// CHECK: extension OldSchool : Swift.UnsafeConcurrentValue {
110+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
111+
// CHECK-NEXT: extension OldSchool : Swift.UnsafeConcurrentValue {
98112
extension OldSchool: UnsafeConcurrentValue { }
99113
// CHECK-NEXT: }
100114

0 commit comments

Comments
 (0)