Skip to content

Commit 7177d90

Browse files
authored
Merge pull request #73492 from kavon/ncgeneric-avoid-spam
NCGenerics: avoid feature-guarding in some cases
2 parents d63d6c8 + f0f91ee commit 7177d90

File tree

4 files changed

+85
-12
lines changed

4 files changed

+85
-12
lines changed

lib/AST/FeatureSet.cpp

+37-8
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,21 @@ UNINTERESTING_FEATURE(Embedded)
506506
UNINTERESTING_FEATURE(Volatile)
507507
UNINTERESTING_FEATURE(SuppressedAssociatedTypes)
508508

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

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

test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift

+15
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

-4
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

+33
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,39 @@ import NoncopyableGenerics_Misc
160160
// CHECK-MISC-NEXT: public func suppressesNoncopyableGenerics<T>(_ t: borrowing T) where T : ~Copyable
161161
// CHECK-MISC-NEXT: #endif
162162

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

164197
import Swiftskell
165198

0 commit comments

Comments
 (0)