From a904fee7fe22e02c4bd1a22a6f28768db33997e8 Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Thu, 15 May 2025 10:21:22 -0700 Subject: [PATCH] [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. --- lib/IRGen/GenMeta.cpp | 28 ++++++++------- .../layout_string_witnesses_types.swift | 20 +++++++++++ .../layout_string_witnesses_dynamic.swift | 36 +++++++++++++++++++ 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 62facbd61f240..930845118ee46 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -6014,12 +6014,14 @@ namespace { if (!layoutStringsEnabled(IGM)) { return false; } - return !!getLayoutString() || - (IGM.Context.LangOpts.hasFeature( - Feature::LayoutStringValueWitnessesInstantiation) && - IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation && - (HasDependentVWT || HasDependentMetadata) && - !isa(IGM.getTypeInfo(getLoweredType()))); + const auto &TI = IGM.getTypeInfo(getLoweredType()); + return (!!getLayoutString() || + (IGM.Context.LangOpts.hasFeature( + Feature::LayoutStringValueWitnessesInstantiation) && + IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation && + (HasDependentVWT || HasDependentMetadata) && + !isa(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(IGM.getTypeInfo(getLoweredType()))); + return (!!getLayoutString() || + (IGM.Context.LangOpts.hasFeature( + Feature::LayoutStringValueWitnessesInstantiation) && + IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation && + (HasDependentVWT || HasDependentMetadata) && + !isa(TI))) && + TI.isCopyable(ResilienceExpansion::Maximal); } llvm::Constant *emitNominalTypeDescriptor() { diff --git a/test/Interpreter/Inputs/layout_string_witnesses_types.swift b/test/Interpreter/Inputs/layout_string_witnesses_types.swift index 65060bfb66c72..b1bb42bd254fe 100644 --- a/test/Interpreter/Inputs/layout_string_witnesses_types.swift +++ b/test/Interpreter/Inputs/layout_string_witnesses_types.swift @@ -673,6 +673,21 @@ public enum MultiPayloadAnyObject { case z(AnyObject) } +public struct NonCopyableGenericStruct: ~Copyable { + let x: Int + let y: T + + public init(x: Int, y: T) { + self.x = x + self.y = y + } +} + +public enum NonCopyableGenericEnum: ~Copyable { + case x(Int, T?) + case y(Int) +} + @inline(never) public func consume(_ x: T.Type) { withExtendedLifetime(x) {} @@ -751,6 +766,11 @@ public func testGenericArrayDestroy(_ buffer: UnsafeMutableBufferPointer) buffer.deinitialize() } +@inline(never) +public func testGenericArrayDestroy(_ buffer: UnsafeMutableBufferPointer) { + buffer.deinitialize() +} + @inline(never) public func testGenericArrayInitWithCopy(dest: UnsafeMutableBufferPointer, src: UnsafeMutableBufferPointer) { _ = dest.initialize(fromContentsOf: src) diff --git a/test/Interpreter/layout_string_witnesses_dynamic.swift b/test/Interpreter/layout_string_witnesses_dynamic.swift index 418ebbabfc064..b91bf03a1a068 100644 --- a/test/Interpreter/layout_string_witnesses_dynamic.swift +++ b/test/Interpreter/layout_string_witnesses_dynamic.swift @@ -1239,6 +1239,42 @@ func testGenericResilientWithUnmanagedAndWeak() { testGenericResilientWithUnmanagedAndWeak() +func testNonCopyableGenericStructSimpleClass() { + let ptr = UnsafeMutableBufferPointer>.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>.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