diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs index e2a5d65d0..2690a0a7a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs @@ -530,6 +530,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty num.ToString(); } +#if CS73 + private unsafe static int Issue2287(ref StructWithFixedSizeMembers value) + { + return value.Integers[0] + value.Integers[1]; + } +#endif + private unsafe static void* CastToVoidPtr(IntPtr intptr) { return (void*)intptr; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 49e523971..a8c3443f9 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -2818,8 +2818,22 @@ namespace ICSharpCode.Decompiler.CSharp .WithILInstruction(inst); if (inst.ResultType == StackType.Ref) { - // convert pointer back to ref - return result.ConvertTo(new ByReferenceType(elementType), this); + // `target.field` has pointer-type. + if (inst.SlotInfo == PinnedRegion.InitSlot || inst.Parent is Conv { TargetType: IL.PrimitiveType.U }) + { + // Convert pointer to ref if we're in a context where we're going to convert + // the ref back to a pointer. + return result.ConvertTo(new ByReferenceType(elementType), this); + } + else + { + // We can't use `ref *target.field` unless `target` is non-movable, + // but we can use `ref target.field[0]`. + var arrayAccess = new IndexerExpression(result, new PrimitiveExpression(0)) + .WithRR(new ResolveResult(elementType)); + return new DirectionExpression(FieldDirection.Ref, arrayAccess) + .WithoutILInstruction().WithRR(new ByReferenceResolveResult(arrayAccess.ResolveResult, ReferenceKind.Ref)); + } } else {