Skip to content

Commit 53b5920

Browse files
committed
Reject fixed expressions when used with static GetPinnableReference method
1 parent 4d00bb5 commit 53b5920

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

src/Compiler/Checking/CheckExpressions.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10343,7 +10343,7 @@ and TcAndBuildFixedExpr (cenv: cenv) env (overallPatTy, fixedExpr, overallExprTy
1034310343
|> List.tryFind (fun mInfo ->
1034410344
// GetPinnableReference must be a parameterless method with a byref or inref return value
1034510345
match mInfo.GetParamDatas(cenv.amap, mBinding, mInfo.FormalMethodInst), mInfo.GetFSharpReturnType(cenv.amap, mBinding, mInfo.FormalMethodInst) with
10346-
| [[]], retTy when isByrefTy g retTy -> true
10346+
| [[]], retTy when isByrefTy g retTy && mInfo.IsInstance -> true
1034710347
| _ -> false
1034810348
)
1034910349

tests/FSharp.Compiler.ComponentTests/EmittedIL/FixedExpressionTests.fs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,55 @@ let main _ =
606606
IL_0016: ldobj [runtime]System.Int32
607607
IL_001b: ret
608608
} """ ]
609+
610+
[<Fact>]
611+
let ``Pin type with extension method GetPinnableReference : unit -> byref<T>`` () =
612+
Fsx """
613+
module FixedExpressions
614+
open System.Runtime.CompilerServices
615+
open Microsoft.FSharp.NativeInterop
616+
617+
type RefField<'T> = { mutable _value: 'T }
618+
619+
[<Extension>]
620+
type RefFieldExtensions =
621+
[<Extension>]
622+
static member GetPinnableReference(refField: RefField<'T>) : byref<'T> = &refField._value
623+
624+
let pinIt (thing: RefField<'T>) =
625+
use ptr = fixed thing
626+
NativePtr.get ptr 0
627+
628+
[<EntryPoint>]
629+
let main _ =
630+
let mutable x = 42
631+
let refToX = { _value = x }
632+
let y = pinIt refToX
633+
if y <> x then failwith "y did not equal x"
634+
0
635+
"""
636+
|> withOptions ["--nowarn:9"]
637+
|> compileExeAndRun
638+
|> shouldSucceed
639+
|> verifyIL ["""
640+
.method public static !!a pinIt<T,a>(class FixedExpressions/RefField`1<!!T> thing) cil managed
641+
{
642+
643+
.maxstack 5
644+
.locals init (native int V_0,
645+
!!a& pinned V_1)
646+
IL_0000: ldarg.0
647+
IL_0001: ldflda !0 class FixedExpressions/RefField`1<!!a>::_value@
648+
IL_0006: stloc.1
649+
IL_0007: ldloc.1
650+
IL_0008: conv.i
651+
IL_0009: stloc.0
652+
IL_000a: ldloc.0
653+
IL_000b: ldc.i4.0
654+
IL_000c: conv.i
655+
IL_000d: sizeof !!a
656+
IL_0013: mul
657+
IL_0014: add
658+
IL_0015: ldobj !!a
659+
IL_001a: ret
660+
} """ ]

tests/FSharp.Compiler.ComponentTests/Language/FixedExpressionTests.fs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,45 @@ let pinIt (thing: RefField<'T>) =
367367
(Warning 9, Line 11, Col 9, Line 11, Col 12, """Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'.""")
368368
(Warning 9, Line 12, Col 5, Line 12, Col 18, """Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'.""")
369369
]
370+
371+
[<Fact>]
372+
let ``Pin type with private method GetPinnableReference - illegal`` () =
373+
Fsx """
374+
open Microsoft.FSharp.NativeInterop
375+
376+
type StrangeType<'T>(_value) =
377+
let mutable _value = _value
378+
member private this.GetPinnableReference() : byref<'T> = _value
379+
380+
let pinIt (thing: StrangeType<'T>) =
381+
use ptr = fixed thing
382+
NativePtr.get ptr 0
383+
"""
384+
|> ignoreWarnings
385+
|> typecheck
386+
|> shouldFail
387+
|> withDiagnostics [
388+
(Warning 9, Line 9, Col 9, Line 9, Col 12, """Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'.""")
389+
(Error 3207, Line 9, Col 9, Line 9, Col 12, """Invalid use of 'fixed'. 'fixed' may only be used in a declaration of the form 'use x = fixed expr' where the expression is an array, the address of a field, the address of an array element or a string'""")
390+
]
391+
392+
[<Fact>]
393+
let ``Pin type with static method GetPinnableReference - illegal`` () =
394+
Fsx """
395+
open Microsoft.FSharp.NativeInterop
396+
397+
type StrangeType<'T>(_value) =
398+
let mutable _value = _value
399+
static member GetPinnableReference() : byref<'T> = Unchecked.defaultof<'T>
400+
401+
let pinIt (thing: StrangeType<'T>) =
402+
use ptr = fixed thing
403+
NativePtr.get ptr 0
404+
"""
405+
|> ignoreWarnings
406+
|> typecheck
407+
|> shouldFail
408+
|> withDiagnostics [
409+
(Warning 9, Line 9, Col 9, Line 9, Col 12, """Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'.""")
410+
(Error 3207, Line 9, Col 9, Line 9, Col 12, """Invalid use of 'fixed'. 'fixed' may only be used in a declaration of the form 'use x = fixed expr' where the expression is an array, the address of a field, the address of an array element or a string'""")
411+
]

0 commit comments

Comments
 (0)