Skip to content

Commit 97da8c7

Browse files
authored
Merge pull request #73533 from kavon/6.0-ncgeneric-avoid-spam
[6.0🍒] NCGenerics: avoid feature-guarding in some cases
2 parents f94a72d + 35be4a1 commit 97da8c7

File tree

4 files changed

+85
-12
lines changed

4 files changed

+85
-12
lines changed

lib/AST/FeatureSet.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,21 @@ static bool usesFeatureRawLayout(Decl *decl) {
504504
UNINTERESTING_FEATURE(Embedded)
505505
UNINTERESTING_FEATURE(SuppressedAssociatedTypes)
506506

507+
static bool disallowFeatureSuppression(StringRef featureName, Decl *decl);
508+
509+
static bool allBoundTypesAreCopyable(Type type, DeclContext *context) {
510+
assert(type->getAnyNominal());
511+
auto bgt = type->getAs<BoundGenericType>();
512+
if (!bgt)
513+
return false; // nothing is bound.
514+
515+
for (auto argInterfaceTy : bgt->getGenericArgs())
516+
if (context->mapTypeIntoContext(argInterfaceTy)->isNoncopyable())
517+
return false;
518+
519+
return true;
520+
}
521+
507522
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
508523
if (decl->getAttrs().hasAttribute<PreInverseGenericsAttr>())
509524
return true;
@@ -521,15 +536,29 @@ static bool usesFeatureNoncopyableGenerics(Decl *decl) {
521536

522537
if (isa<AbstractFunctionDecl>(valueDecl) ||
523538
isa<AbstractStorageDecl>(valueDecl)) {
524-
if (valueDecl->getInterfaceType().findIf([&](Type type) -> bool {
525-
if (auto *nominalDecl = type->getAnyNominal()) {
526-
if (isa<StructDecl, EnumDecl, ClassDecl>(nominalDecl))
527-
return usesFeatureNoncopyableGenerics(nominalDecl);
528-
}
529-
return false;
530-
})) {
539+
auto *context = decl->getInnermostDeclContext();
540+
auto usesFeature = valueDecl->getInterfaceType().findIf(
541+
[&](Type type) -> bool {
542+
auto *nominalDecl = type->getAnyNominal();
543+
if (!nominalDecl || !isa<StructDecl, EnumDecl, ClassDecl>(nominalDecl))
544+
return false;
545+
546+
if (!usesFeatureNoncopyableGenerics(nominalDecl))
547+
return false;
548+
549+
// If we only _refer_ to a TypeDecl that uses NoncopyableGenerics,
550+
// and a suppressed version of that decl is in the interface, then we're
551+
// only referring to the un-suppressed version if any of the bound types
552+
// are noncopyable. (rdar://127389991)
553+
if (!disallowFeatureSuppression("NoncopyableGenerics", nominalDecl)
554+
&& allBoundTypesAreCopyable(type, context)) {
555+
return false;
556+
}
557+
558+
return true;
559+
});
560+
if (usesFeature)
531561
return true;
532-
}
533562
}
534563
}
535564

test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,18 @@ public func borrowsNoncopyable<T: ~Copyable>(_ t: borrowing T) {}
112112

113113
@_disallowFeatureSuppression(NoncopyableGenerics)
114114
public func suppressesNoncopyableGenerics<T: ~Copyable>(_ t: borrowing T) {}
115+
116+
// coverage for rdar://127389991
117+
@_disallowFeatureSuppression(NoncopyableGenerics)
118+
public struct LoudlyNC<T: ~Copyable> {}
119+
public func _indexHumongousDonuts<TTT, T>(_ aggregate: UnsafePointer<TTT>, _ index: Int) -> T {
120+
return UnsafeRawPointer(aggregate).load(
121+
fromByteOffset: index * MemoryLayout<T>.stride, as: T.self)
122+
}
123+
public func referToLoud(_ t: LoudlyNC<String>) {}
124+
@_disallowFeatureSuppression(NoncopyableGenerics) public func referToLoudProperGuarding(_ t: LoudlyNC<String>) {}
125+
public struct NoCopyPls: ~Copyable {}
126+
public func substCopyable(_ t: String?) {}
127+
public func substGenericCopyable<T>(_ t: T?) {}
128+
public func substNC(_ t: borrowing NoCopyPls?) {}
129+
public func substGenericNC<T: ~Copyable>(_ t: borrowing T?) {}

test/ModuleInterface/features.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,9 @@ public class OldSchool2: MP {
9090
// CHECK: public struct UsesRP {
9191
public struct UsesRP {
9292
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
93-
// CHECK-NEXT: #if $NoncopyableGenerics
9493
// CHECK-NEXT: public var value: (any FeatureTest.RP)? {
9594
// CHECK-NOT: #if compiler(>=5.3) && $RethrowsProtocol
9695
// CHECK: get
97-
// CHECK: #else
98-
// CHECK-NEXT: public var value: (any FeatureTest.RP)? {
99-
// CHECK-NEXT: get
10096
public var value: RP? {
10197
nil
10298
}

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,39 @@ import NoncopyableGenerics_Misc
165165
// CHECK-MISC-NEXT: public func suppressesNoncopyableGenerics<T>(_ t: borrowing T) where T : ~Copyable
166166
// CHECK-MISC-NEXT: #endif
167167

168+
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
169+
// CHECK-MISC-NEXT: public struct LoudlyNC<T> where T : ~Copyable {
170+
// CHECK-MISC-NEXT: }
171+
// CHECK-MISC-NEXT: #endif
172+
// CHECK-MISC-NEXT: public func _indexHumongousDonuts<TTT, T>(_ aggregate: Swift.UnsafePointer<TTT>, _ index: Swift.Int) -> T
173+
// CHECK-MISC-NEXT: #if compiler(>=5.3) && $NoncopyableGenerics
174+
// CHECK-MISC-NEXT: public func referToLoud(_ t: {{.*}}.LoudlyNC<Swift.String>)
175+
// CHECK-MISC-NEXT: #else
176+
// CHECK-MISC-NEXT: public func referToLoud(_ t: {{.*}}.LoudlyNC<Swift.String>)
177+
// CHECK-MISC-NEXT: #endif
178+
// CHECK-MISC-NEXT: #if compiler(>=5.3) && $NoncopyableGenerics
179+
// CHECK-MISC-NEXT: public func referToLoudProperGuarding(_ t: {{.*}}.LoudlyNC<Swift.String>)
180+
// CHECK-MISC-NEXT: #endif
181+
// CHECK-MISC-NEXT: public struct NoCopyPls : ~Swift.Copyable {
182+
// CHECK-MISC-NEXT: }
183+
// CHECK-MISC-NEXT: public func substCopyable(_ t: Swift.String?)
184+
// CHECK-MISC-NEXT: public func substGenericCopyable<T>(_ t: T?)
185+
186+
// NOTE: we really shouldn't be emitting the else branch for the two funcs
187+
// below, since the suppressed version isn't valid. We don't have a good way of
188+
// fixing that right now, either.
189+
190+
// CHECK-MISC-NEXT: #if compiler(>=5.3) && $NoncopyableGenerics
191+
// CHECK-MISC-NEXT: public func substNC(_ t: borrowing {{.*}}.NoCopyPls?)
192+
// CHECK-MISC-NEXT: #else
193+
// CHECK-MISC-NEXT: public func substNC(_ t: borrowing {{.*}}.NoCopyPls?)
194+
// CHECK-MISC-NEXT: #endif
195+
// CHECK-MISC-NEXT: #if compiler(>=5.3) && $NoncopyableGenerics
196+
// CHECK-MISC-NEXT: public func substGenericNC<T>(_ t: borrowing T?) where T : ~Copyable
197+
// CHECK-MISC-NEXT: #else
198+
// CHECK-MISC-NEXT: public func substGenericNC<T>(_ t: borrowing T?)
199+
// CHECK-MISC-NEXT: #endif
200+
168201

169202
import Swiftskell
170203

0 commit comments

Comments
 (0)