diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ElementsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ElementsMarshalling.cs
index f21125e297aa7e..c547efe7e46d53 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ElementsMarshalling.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ElementsMarshalling.cs
@@ -105,6 +105,16 @@ ExpressionSyntax GetExpressionForParam(TypePositionInfo paramInfo)
public abstract StatementSyntax GenerateUnmarshalStatement(StubIdentifierContext context);
public abstract StatementSyntax GenerateElementCleanupStatement(StubIdentifierContext context);
+
+ ///
+ ///
+ /// <numElements> = <GetManagedValuesSource>.Length;
+ ///
+ ///
+ public StatementSyntax GenerateNumElementsAssignmentFromManagedValuesSource(StubIdentifierContext context)
+ {
+ return CollectionSource.GetNumElementsAssignmentFromManagedValuesSource(CollectionSource.TypeInfo, context);
+ }
}
file static class ElementsMarshallingCollectionSourceExtensions
@@ -366,6 +376,7 @@ public override StatementSyntax GenerateManagedToUnmanagedByValueOutUnmarshalSta
public override StatementSyntax GenerateElementCleanupStatement(StubIdentifierContext context)
{
string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(CollectionSource.TypeInfo, context);
+ string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(CollectionSource.TypeInfo, context);
ExpressionSyntax indexConstraintName;
if (!UsesLastIndexMarshalled(CollectionSource.TypeInfo, CollectionSource.CodeContext))
{
@@ -394,13 +405,32 @@ public override StatementSyntax GenerateElementCleanupStatement(StubIdentifierCo
return EmptyStatement();
}
+ // Declare the managed span so that nested element cleanup can access it via []
+ // (e.g., when an inner stateless collection with NoCountInfo needs to compute its length from the
+ // managed source during ManagedToUnmanaged cleanup).
+ bool isManagedToUnmanaged = MarshallerHelpers.GetMarshalDirection(CollectionSource.TypeInfo, CollectionSource.CodeContext) == MarshalDirection.ManagedToUnmanaged;
+ LocalDeclarationStatementSyntax nativeSpanDeclaration = Declare(
+ ReadOnlySpanOf(unmanagedElementType),
+ nativeSpanIdentifier,
+ isManagedToUnmanaged
+ ? CollectionSource.GetUnmanagedValuesDestination(context)
+ : CollectionSource.GetUnmanagedValuesSource(context));
+
+ if (isManagedToUnmanaged)
+ {
+ LocalDeclarationStatementSyntax managedSpanDeclaration = Declare(
+ ReadOnlySpanOf(elementMarshaller.TypeInfo.ManagedType.Syntax),
+ managedSpanIdentifier,
+ CollectionSource.GetManagedValuesSource(context));
+
+ return Block(
+ nativeSpanDeclaration,
+ managedSpanDeclaration,
+ contentsCleanupStatements);
+ }
+
return Block(
- Declare(
- ReadOnlySpanOf(unmanagedElementType),
- nativeSpanIdentifier,
- MarshallerHelpers.GetMarshalDirection(CollectionSource.TypeInfo, CollectionSource.CodeContext) == MarshalDirection.ManagedToUnmanaged
- ? CollectionSource.GetUnmanagedValuesDestination(context)
- : CollectionSource.GetUnmanagedValuesSource(context)),
+ nativeSpanDeclaration,
contentsCleanupStatements);
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs
index da13f490614238..31363037d8f2b1 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs
@@ -581,15 +581,9 @@ public IEnumerable GenerateCleanupCallerAllocatedResourcesState
if (countInfo is NoCountInfo && MarshallerHelpers.GetMarshalDirection(TypeInfo, CodeContext) == MarshalDirection.ManagedToUnmanaged)
{
// When marshalling from managed to unmanaged, we may not have count info.
- // For now, just set to 0.
- // See https://github.com/dotnet/runtime/issues/93423 for a tracking issue.
-
- // = 0;
- yield return ExpressionStatement(
- AssignmentExpression(
- SyntaxKind.SimpleAssignmentExpression,
- IdentifierName(numElementsIdentifier),
- LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0))));
+ // Use the managed collection's length to determine the number of elements to clean up.
+ // = .Length;
+ yield return elementsMarshalling.GenerateNumElementsAssignmentFromManagedValuesSource(context);
}
else
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
index 7b853db968adb1..c71eb7b5ede179 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
@@ -314,11 +314,13 @@ public static IEnumerable