[DllImportGenerator] Treat pointer fields in structs as blittable regardless of what...
authorElinor Fung <elfung@microsoft.com>
Sat, 13 Nov 2021 03:08:39 +0000 (19:08 -0800)
committerGitHub <noreply@github.com>
Sat, 13 Nov 2021 03:08:39 +0000 (19:08 -0800)
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.Tests/BlittableStructTests.cs
src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/ManualTypeMarshallingAnalyzerTests.cs
src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/BlittableStructs.cs
src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/Blittable.cs

index 9768e2d..4f5aaf0 100644 (file)
@@ -31,7 +31,7 @@ namespace Microsoft.Interop
                     bool fieldBlittable = field switch
                     {
                         { Type: { IsReferenceType: true } } => false,
-                        { Type: IPointerTypeSymbol ptr } => IsConsideredBlittable(ptr.PointedAtType),
+                        { Type: IPointerTypeSymbol ptr } => true,
                         { Type: IFunctionPointerTypeSymbol } => true,
                         not { Type: { SpecialType: SpecialType.None } } => IsSpecialTypeBlittable(field.Type.SpecialType),
                         // Assume that type parameters that can be blittable are blittable.
index 5aa24bf..8fcc270 100644 (file)
@@ -29,12 +29,23 @@ namespace DllImportGenerator.IntegrationTests
         public static partial void DoubleIntFieldsOutReturn(
             IntFields input,
             out IntFields result);
+
+        [GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_increment_invert_ptrfields_byref")]
+        public static partial void IncrementInvertPointerFieldsByRef(ref PointerFields result);
+
+        [GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_increment_invert_ptrfields_byref")]
+        public static partial void IncrementInvertPointerFieldsByRefIn(in PointerFields result);
+
+        [GeneratedDllImport(NativeExportsNE_Binary, EntryPoint = "blittablestructs_increment_invert_ptrfields_refreturn")]
+        public static partial void IncrementInvertPointerFieldsRefReturn(
+            PointerFields input,
+            ref PointerFields result);
     }
 
     public class BlittableStructTests
     {
         [Fact]
-        public void ValidateBlittableStruct()
+        public void ValidateIntFields()
         {
             const int A = 24, B = 37, C = 59;
             var initial = new IntFields()
@@ -82,5 +93,71 @@ namespace DllImportGenerator.IntegrationTests
                 Assert.Equal(expected, input); // Updated even when passed with in keyword (matches built-in system)
             }
         }
+
+        [Fact]
+        public unsafe void ValidatePointerFields()
+        {
+            int iInitial = 31;
+            bool bInitial = false;
+            char cInitial = 'A';
+
+            int iExpected = iInitial + 1;
+            bool bExpected = !bInitial;
+            char cExpected = (char)(cInitial + 1);
+
+            int i = iInitial;
+            bool b = bInitial;
+            char c = cInitial;
+            var initial = new PointerFields()
+            {
+                i = &i,
+                b = &b,
+                c = &c,
+            };
+
+            PointerFields input = initial;
+            {
+                int iResult;
+                bool bResult;
+                char cResult;
+                var result = new PointerFields()
+                {
+                    i = &iResult,
+                    b = &bResult,
+                    c = &cResult
+                };
+                NativeExportsNE.IncrementInvertPointerFieldsRefReturn(input, ref result);
+                Assert.Equal(initial, input);
+                ValidateFieldValues(result);
+            }
+
+            {
+                ResetFieldValues(input);
+                NativeExportsNE.IncrementInvertPointerFieldsByRef(ref input);
+                Assert.Equal(initial, input);
+                ValidateFieldValues(input);
+            }
+
+            {
+                ResetFieldValues(input);
+                NativeExportsNE.IncrementInvertPointerFieldsByRefIn(in input);
+                Assert.Equal(initial, input);
+                ValidateFieldValues(input);
+            }
+
+            void ResetFieldValues(PointerFields input)
+            {
+                *(input.i) = iInitial;
+                *(input.b) = bInitial;
+                *(input.c) = cInitial;
+            }
+
+            void ValidateFieldValues(PointerFields result)
+            {
+                Assert.Equal(iExpected, *result.i);
+                Assert.Equal(bExpected, *result.b);
+                Assert.Equal(cExpected, *result.c);
+            }
+        }
     }
 }
index ba00865..2938fa3 100644 (file)
@@ -1280,7 +1280,7 @@ struct Native<T>
         }
 
         [ConditionalFact]
-        public async Task ValueTypeContainingPointerBlittableType_DoesNotReportDiagnostic()
+        public async Task ValueTypeContainingPointers_DoesNotReportDiagnostic()
         {
             var source = @"
 using System.Runtime.InteropServices;
@@ -1288,27 +1288,13 @@ using System.Runtime.InteropServices;
 [BlittableType]
 unsafe struct S
 {
-    private int* ptr;
+    private int* intPtr;
+    private bool* boolPtr;
 }";
             await VerifyCS.VerifyAnalyzerAsync(source);
         }
 
         [ConditionalFact]
-        public async Task ValueTypeContainingPointerToNonBlittableType_ReportsDiagnostic()
-        {
-            var source = @"
-using System.Runtime.InteropServices;
-
-[{|#0:BlittableType|}]
-unsafe struct S
-{
-    private bool* ptr;
-}";
-            await VerifyCS.VerifyAnalyzerAsync(source,
-                VerifyCS.Diagnostic(BlittableTypeMustBeBlittableRule).WithLocation(0).WithArguments("S"));
-        }
-
-        [ConditionalFact]
         public async Task BlittableValueTypeContainingPointerToSelf_DoesNotReportDiagnostic()
         {
 
index f9dbaf9..71b3ae5 100644 (file)
@@ -40,5 +40,25 @@ namespace NativeExports
             result->b = input.b * 2;
             result->c = input.c * 2;
         }
+
+        [UnmanagedCallersOnly(EntryPoint = "blittablestructs_increment_invert_ptrfields_byref")]
+        [DNNE.C99DeclCode("struct ptr_fields { int* i; int* b; uint16_t* c; };")]
+        public static void IncrementInvertPointerFieldsByRef(
+            [DNNE.C99Type("struct ptr_fields*")] PointerFields* result)
+        {
+            *(result->i) += 1;
+            *(result->b) = !*(result->b);
+            *(result->c) += (char)1;
+        }
+
+        [UnmanagedCallersOnly(EntryPoint = "blittablestructs_increment_invert_ptrfields_refreturn")]
+        public static void IncrementInvertPointerFieldsRefReturn(
+            [DNNE.C99Type("struct ptr_fields")] PointerFields input,
+            [DNNE.C99Type("struct ptr_fields*")] PointerFields* result)
+        {
+            *(result->i) = *(input.i) + 1;
+            *(result->b) = !(*input.b);
+            *(result->c) = (char)(*(input.c) + 1);
+        }
     }
 }
index dec9f74..fc25816 100644 (file)
@@ -13,4 +13,12 @@ namespace SharedTypes
         public int b;
         public int c;
     }
+
+    [BlittableType]
+    public unsafe struct PointerFields
+    {
+        public int* i;
+        public bool* b;
+        public char* c;
+    }
 }