[IRGen] Don't set HasLayoutString flag on non-copyable generic types

rdar://151176697

While generic types generally have layout strings (when enabled), non-copyable types don't, so
we have to make sure the flag does not get set.
This commit is contained in:
Dario Rexin
2025-05-15 10:21:22 -07:00
parent ee3aca2ef3
commit 75c581d3a0
3 changed files with 72 additions and 12 deletions

View File

@@ -6014,12 +6014,14 @@ namespace {
if (!layoutStringsEnabled(IGM)) {
return false;
}
return !!getLayoutString() ||
(IGM.Context.LangOpts.hasFeature(
Feature::LayoutStringValueWitnessesInstantiation) &&
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
(HasDependentVWT || HasDependentMetadata) &&
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())));
const auto &TI = IGM.getTypeInfo(getLoweredType());
return (!!getLayoutString() ||
(IGM.Context.LangOpts.hasFeature(
Feature::LayoutStringValueWitnessesInstantiation) &&
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
(HasDependentVWT || HasDependentMetadata) &&
!isa<FixedTypeInfo>(TI))) &&
TI.isCopyable(ResilienceExpansion::Maximal);
}
llvm::Constant *emitNominalTypeDescriptor() {
@@ -6547,13 +6549,15 @@ namespace {
if (!layoutStringsEnabled(IGM)) {
return false;
}
auto &TI = IGM.getTypeInfo(getLoweredType());
return !!getLayoutString() ||
(IGM.Context.LangOpts.hasFeature(
Feature::LayoutStringValueWitnessesInstantiation) &&
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
(HasDependentVWT || HasDependentMetadata) &&
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())));
return (!!getLayoutString() ||
(IGM.Context.LangOpts.hasFeature(
Feature::LayoutStringValueWitnessesInstantiation) &&
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
(HasDependentVWT || HasDependentMetadata) &&
!isa<FixedTypeInfo>(TI))) &&
TI.isCopyable(ResilienceExpansion::Maximal);
}
llvm::Constant *emitNominalTypeDescriptor() {

View File

@@ -673,6 +673,21 @@ public enum MultiPayloadAnyObject {
case z(AnyObject)
}
public struct NonCopyableGenericStruct<T>: ~Copyable {
let x: Int
let y: T
public init(x: Int, y: T) {
self.x = x
self.y = y
}
}
public enum NonCopyableGenericEnum<T>: ~Copyable {
case x(Int, T?)
case y(Int)
}
@inline(never)
public func consume<T>(_ x: T.Type) {
withExtendedLifetime(x) {}
@@ -751,6 +766,11 @@ public func testGenericArrayDestroy<T>(_ buffer: UnsafeMutableBufferPointer<T>)
buffer.deinitialize()
}
@inline(never)
public func testGenericArrayDestroy<T: ~Copyable>(_ buffer: UnsafeMutableBufferPointer<T>) {
buffer.deinitialize()
}
@inline(never)
public func testGenericArrayInitWithCopy<T>(dest: UnsafeMutableBufferPointer<T>, src: UnsafeMutableBufferPointer<T>) {
_ = dest.initialize(fromContentsOf: src)

View File

@@ -1239,6 +1239,42 @@ func testGenericResilientWithUnmanagedAndWeak() {
testGenericResilientWithUnmanagedAndWeak()
func testNonCopyableGenericStructSimpleClass() {
let ptr = UnsafeMutableBufferPointer<NonCopyableGenericStruct<SimpleClass>>.allocate(capacity: 1)
let x = NonCopyableGenericStruct(x: 23, y: SimpleClass(x: 23))
ptr[0] = x
// CHECK-NEXT: Before deinit
print("Before deinit")
// CHECK-NEXT: SimpleClass deinitialized!
testGenericArrayDestroy(ptr)
ptr.deallocate()
}
testNonCopyableGenericStructSimpleClass()
func testNonCopyableGenericEnumSimpleClass() {
let ptr = UnsafeMutableBufferPointer<NonCopyableGenericEnum<SimpleClass>>.allocate(capacity: 1)
let x = NonCopyableGenericEnum.x(23, SimpleClass(x: 23))
ptr[0] = x
// CHECK-NEXT: Before deinit
print("Before deinit")
// CHECK-NEXT: SimpleClass deinitialized!
testGenericArrayDestroy(ptr)
ptr.deallocate()
}
testNonCopyableGenericEnumSimpleClass()
#if os(macOS)
import Foundation