Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,7 @@ type ILTypeDefLayout =
| Auto
| Sequential of ILTypeDefLayoutInfo
| Explicit of ILTypeDefLayoutInfo (* REVIEW: add field info here *)
| Extended

and ILTypeDefLayoutInfo =
{
Expand Down Expand Up @@ -2632,6 +2633,10 @@ let convertLayout layout =
| ILTypeDefLayout.Auto -> TypeAttributes.AutoLayout
| ILTypeDefLayout.Sequential _ -> TypeAttributes.SequentialLayout
| ILTypeDefLayout.Explicit _ -> TypeAttributes.ExplicitLayout
| ILTypeDefLayout.Extended ->
// Extended layout is represented by TypeAttributes value 0x18 (both Sequential and Explicit bits set)
// This is defined by the ECMA-335 spec for extended layout types
enum<TypeAttributes> (0x18)

let convertEncoding encoding =
match encoding with
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/AbstractIL/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,7 @@ type ILTypeDefLayout =
| Auto
| Sequential of ILTypeDefLayoutInfo
| Explicit of ILTypeDefLayoutInfo
| Extended

type internal ILTypeDefLayoutInfo =
{ Size: int32 option
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/AbstractIL/ilprint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ let splitTypeLayout =
| ILTypeDefLayout.Auto -> "auto", (fun _os () -> ())
| ILTypeDefLayout.Sequential info -> "sequential", (fun os () -> output_type_layout_info os info)
| ILTypeDefLayout.Explicit info -> "explicit", (fun os () -> output_type_layout_info os info)
| ILTypeDefLayout.Extended -> "extended", (fun _os () -> ())

let goutput_fdefs tref env os (fdefs: ILFieldDefs) =
for f in fdefs.AsList() do
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/AbstractIL/ilread.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2044,6 +2044,8 @@ and typeLayoutOfFlags (ctxt: ILMetadataReader) mdv flags tidx =
ILTypeDefLayout.Sequential(seekReadClassLayout ctxt mdv tidx)
elif f = 0x00000010 then
ILTypeDefLayout.Explicit(seekReadClassLayout ctxt mdv tidx)
elif f = 0x00000018 then
ILTypeDefLayout.Extended
else
ILTypeDefLayout.Auto

Expand Down
1 change: 1 addition & 0 deletions src/Compiler/AbstractIL/ilreflect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,7 @@ let typeAttributesOfTypeLayout cenv emEnv x =
| ILTypeDefLayout.Auto -> None
| ILTypeDefLayout.Explicit p -> (attr 0x02 p)
| ILTypeDefLayout.Sequential p -> (attr 0x00 p)
| ILTypeDefLayout.Extended -> None // No StructLayoutAttribute needed; user's ExtendedLayoutAttribute is preserved

//----------------------------------------------------------------------------
// buildTypeDefPass1 cenv
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/AbstractIL/ilwrite.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2883,6 +2883,7 @@ let rec GenTypeDefPass3 enc cenv (tdef: ILTypeDef) =
// ClassLayout entry if needed
match tdef.Layout with
| ILTypeDefLayout.Auto -> ()
| ILTypeDefLayout.Extended -> () // No ClassLayout row for Extended; bits are in TypeAttributes
| ILTypeDefLayout.Sequential layout | ILTypeDefLayout.Explicit layout ->
if Option.isSome layout.Pack || Option.isSome layout.Size then
AddUnsharedRow cenv TableNames.ClassLayout
Expand Down
27 changes: 27 additions & 0 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3416,6 +3416,7 @@ module EstablishTypeDefinitionCores =
let hasMeasureableAttr = HasFSharpAttribute g g.attrib_MeasureableAttribute attrs

let structLayoutAttr = TryFindFSharpInt32Attribute g g.attrib_StructLayoutAttribute attrs
let hasExtendedLayoutAttr = HasFSharpAttributeOpt g g.attrib_ExtendedLayoutAttribute_opt attrs
let hasAllowNullLiteralAttr = TryFindFSharpBoolAttribute g g.attrib_AllowNullLiteralAttribute attrs = Some true

if hasAbstractAttr then
Expand All @@ -3436,7 +3437,13 @@ module EstablishTypeDefinitionCores =

let structLayoutAttributeCheck allowed =
let explicitKind = int32 System.Runtime.InteropServices.LayoutKind.Explicit
// LayoutKind.Extended will have enum value 1 in future .NET versions (currently unused slot)
// It cannot be specified via StructLayoutAttribute - users must use ExtendedLayoutAttribute instead
// See: https://github.com/dotnet/runtime/issues/102727
let extendedLayoutKind = 1
match structLayoutAttr with
| Some kind when kind = extendedLayoutKind ->
errorR (Error(FSComp.SR.tcInvalidStructLayoutExtendedKind(), m))
| Some kind ->
if allowed then
if kind = explicitKind then
Expand All @@ -3446,6 +3453,22 @@ module EstablishTypeDefinitionCores =
else
errorR (Error(FSComp.SR.tcGenericTypesCannotHaveStructLayout(), m))
| None -> ()

let extendedLayoutAttributeCheck () =
if hasExtendedLayoutAttr then
// Check runtime support
match g.attrib_ExtendedLayoutAttribute_opt with
| None ->
errorR (Error(FSComp.SR.tcRuntimeDoesNotSupportExtendedLayoutTypes(), m))
| Some _ -> ()

// Check not combined with StructLayoutAttribute
if structLayoutAttr.IsSome then
errorR (Error(FSComp.SR.tcStructLayoutAndExtendedLayout(), m))

let noExtendedLayoutAttributeCheck () =
if hasExtendedLayoutAttr then
errorR (Error(FSComp.SR.tcOnlyStructsCanHaveExtendedLayout(), m))

let hiddenReprChecks hasRepr =
structLayoutAttributeCheck false
Expand Down Expand Up @@ -3684,17 +3707,20 @@ module EstablishTypeDefinitionCores =
if not (isNil slotsigs) then
errorR (Error(FSComp.SR.tcStructTypesCannotContainAbstractMembers(), m))
structLayoutAttributeCheck true
extendedLayoutAttributeCheck()

TFSharpStruct
| SynTypeDefnKind.Interface ->
if hasSealedAttr = Some true then errorR (Error(FSComp.SR.tcInterfaceTypesCannotBeSealed(), m))
structLayoutAttributeCheck false
noExtendedLayoutAttributeCheck()
noAbstractClassAttributeCheck()
allowNullLiteralAttributeCheck()
noFieldsCheck userFields
TFSharpInterface
| SynTypeDefnKind.Class ->
structLayoutAttributeCheck(not isIncrClass)
noExtendedLayoutAttributeCheck()
allowNullLiteralAttributeCheck()
for slot in abstractSlots do
if not slot.IsInstanceMember then
Expand All @@ -3703,6 +3729,7 @@ module EstablishTypeDefinitionCores =
| SynTypeDefnKind.Delegate (ty, arity) ->
noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedDelegate
structLayoutAttributeCheck false
noExtendedLayoutAttributeCheck()
noAllowNullLiteralAttributeCheck()
noAbstractClassAttributeCheck()
noFieldsCheck userFields
Expand Down
109 changes: 57 additions & 52 deletions src/Compiler/CodeGen/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11564,60 +11564,64 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option
tdef

let tdLayout, tdEncoding =
match TryFindFSharpAttribute g g.attrib_StructLayoutAttribute tycon.Attribs with
| Some(Attrib(_, _, [ AttribInt32Arg layoutKind ], namedArgs, _, _, _)) ->
let decoder = AttributeDecoder namedArgs
let ilPack = decoder.FindInt32 "Pack" 0x0
let ilSize = decoder.FindInt32 "Size" 0x0

let tdEncoding =
match (decoder.FindInt32 "CharSet" 0x0) with
(* enumeration values for System.Runtime.InteropServices.CharSet taken from mscorlib.il *)
| 0x03 -> ILDefaultPInvokeEncoding.Unicode
| 0x04 -> ILDefaultPInvokeEncoding.Auto
| _ -> ILDefaultPInvokeEncoding.Ansi

let layoutInfo =
if ilPack = 0x0 && ilSize = 0x0 then
{ Size = None; Pack = None }
else
{
Size = Some ilSize
Pack = Some(uint16 ilPack)
}

let tdLayout =
match layoutKind with
(* enumeration values for System.Runtime.InteropServices.LayoutKind taken from mscorlib.il *)
| 0x0 -> ILTypeDefLayout.Sequential layoutInfo
| 0x2 -> ILTypeDefLayout.Explicit layoutInfo
| _ -> ILTypeDefLayout.Auto

tdLayout, tdEncoding
| Some(Attrib(_, _, _, _, _, _, m)) ->
errorR (Error(FSComp.SR.ilStructLayoutAttributeCouldNotBeDecoded (), m))
ILTypeDefLayout.Auto, ILDefaultPInvokeEncoding.Ansi

| _ when
(match ilTypeDefKind with
| HasFlag ILTypeDefAdditionalFlags.ValueType -> true
| _ -> false)
->
// Check for ExtendedLayoutAttribute first
if HasFSharpAttributeOpt g g.attrib_ExtendedLayoutAttribute_opt tycon.Attribs then
ILTypeDefLayout.Extended, ILDefaultPInvokeEncoding.Ansi
else
match TryFindFSharpAttribute g g.attrib_StructLayoutAttribute tycon.Attribs with
| Some(Attrib(_, _, [ AttribInt32Arg layoutKind ], namedArgs, _, _, _)) ->
let decoder = AttributeDecoder namedArgs
let ilPack = decoder.FindInt32 "Pack" 0x0
let ilSize = decoder.FindInt32 "Size" 0x0

let tdEncoding =
match (decoder.FindInt32 "CharSet" 0x0) with
(* enumeration values for System.Runtime.InteropServices.CharSet taken from mscorlib.il *)
| 0x03 -> ILDefaultPInvokeEncoding.Unicode
| 0x04 -> ILDefaultPInvokeEncoding.Auto
| _ -> ILDefaultPInvokeEncoding.Ansi

let layoutInfo =
if ilPack = 0x0 && ilSize = 0x0 then
{ Size = None; Pack = None }
else
{
Size = Some ilSize
Pack = Some(uint16 ilPack)
}

// All structs are sequential by default
// Structs with no instance fields get size 1, pack 0
if
tycon.AllFieldsArray |> Array.exists (fun f -> not f.IsStatic)
||
// Reflection emit doesn't let us emit 'pack' and 'size' for generic structs.
// In that case we generate a dummy field instead
(cenv.options.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty)
then
ILTypeDefLayout.Sequential { Size = None; Pack = None }, ILDefaultPInvokeEncoding.Ansi
else
ILTypeDefLayout.Sequential { Size = Some 1; Pack = Some 0us }, ILDefaultPInvokeEncoding.Ansi
let tdLayout =
match layoutKind with
(* enumeration values for System.Runtime.InteropServices.LayoutKind taken from mscorlib.il *)
| 0x0 -> ILTypeDefLayout.Sequential layoutInfo
| 0x2 -> ILTypeDefLayout.Explicit layoutInfo
| _ -> ILTypeDefLayout.Auto

tdLayout, tdEncoding
| Some(Attrib(_, _, _, _, _, _, m)) ->
errorR (Error(FSComp.SR.ilStructLayoutAttributeCouldNotBeDecoded (), m))
ILTypeDefLayout.Auto, ILDefaultPInvokeEncoding.Ansi

| _ when
(match ilTypeDefKind with
| HasFlag ILTypeDefAdditionalFlags.ValueType -> true
| _ -> false)
->

// All structs are sequential by default
// Structs with no instance fields get size 1, pack 0
if
tycon.AllFieldsArray |> Array.exists (fun f -> not f.IsStatic)
||
// Reflection emit doesn't let us emit 'pack' and 'size' for generic structs.
// In that case we generate a dummy field instead
(cenv.options.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty)
then
ILTypeDefLayout.Sequential { Size = None; Pack = None }, ILDefaultPInvokeEncoding.Ansi
else
ILTypeDefLayout.Sequential { Size = Some 1; Pack = Some 0us }, ILDefaultPInvokeEncoding.Ansi

| _ -> ILTypeDefLayout.Auto, ILDefaultPInvokeEncoding.Ansi
| _ -> ILTypeDefLayout.Auto, ILDefaultPInvokeEncoding.Ansi

// if the type's layout is Explicit, ensure that each field has a valid offset
let validateExplicit (fdef: ILFieldDef) =
Expand All @@ -11641,6 +11645,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option
match tdLayout with
| ILTypeDefLayout.Explicit _ -> List.iter validateExplicit ilFieldDefs
| ILTypeDefLayout.Sequential _ -> List.iter validateSequential ilFieldDefs
| ILTypeDefLayout.Extended -> List.iter validateSequential ilFieldDefs // Extended layout also disallows FieldOffset
| _ -> ()

let tdef =
Expand Down
4 changes: 4 additions & 0 deletions src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,10 @@ tcTypeAbbreviationHasTypeParametersMissingOnType,"This type abbreviation has one
935,tcAllowNullTypesMayOnlyInheritFromAllowNullTypes,"Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal"
936,tcGenericTypesCannotHaveStructLayout,"Generic types cannot be given the 'StructLayout' attribute"
937,tcOnlyStructsCanHaveStructLayout,"Only structs and classes without primary constructors may be given the 'StructLayout' attribute"
3879,tcStructLayoutAndExtendedLayout,"The attributes 'StructLayoutAttribute' and 'ExtendedLayoutAttribute' cannot be used together on the same type"
3880,tcRuntimeDoesNotSupportExtendedLayoutTypes,"The target runtime does not support extended layout types. ExtendedLayoutAttribute requires a newer runtime."
3881,tcOnlyStructsCanHaveExtendedLayout,"Only structs may be given the 'ExtendedLayoutAttribute'"
3882,tcInvalidStructLayoutExtendedKind,"LayoutKind value 1 (Extended) cannot be specified via StructLayoutAttribute. Use ExtendedLayoutAttribute instead."
938,tcRepresentationOfTypeHiddenBySignature,"The representation of this type is hidden by the signature. It must be given an attribute such as [<Sealed>], [<Class>] or [<Interface>] to indicate the characteristics of the type."
939,tcOnlyClassesCanHaveAbstract,"Only classes may be given the 'AbstractClass' attribute"
940,tcOnlyTypesRepresentingUnitsOfMeasureCanHaveMeasure,"Only types representing units-of-measure may be given the 'Measure' attribute"
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/TypedTree/TcGlobals.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1487,6 +1487,7 @@ type TcGlobals(
member val attrib_IsByRefLikeAttribute_opt = tryFindSysAttrib "System.Runtime.CompilerServices.IsByRefLikeAttribute"
member val attrib_DllImportAttribute = tryFindSysAttrib "System.Runtime.InteropServices.DllImportAttribute"
member val attrib_StructLayoutAttribute = findSysAttrib "System.Runtime.InteropServices.StructLayoutAttribute"
member val attrib_ExtendedLayoutAttribute_opt = tryFindSysAttrib "System.Runtime.InteropServices.ExtendedLayoutAttribute"
member val attrib_TypeForwardedToAttribute = findSysAttrib "System.Runtime.CompilerServices.TypeForwardedToAttribute"
member val attrib_ComVisibleAttribute = findSysAttrib "System.Runtime.InteropServices.ComVisibleAttribute"
member val attrib_ComImportAttribute = tryFindSysAttrib "System.Runtime.InteropServices.ComImportAttribute"
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/TypedTree/TcGlobals.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,8 @@ type internal TcGlobals =

member attrib_StructLayoutAttribute: BuiltinAttribInfo

member attrib_ExtendedLayoutAttribute_opt: BuiltinAttribInfo option

member attrib_StructuralComparisonAttribute: BuiltinAttribInfo

member attrib_StructuralEqualityAttribute: BuiltinAttribInfo
Expand Down
Loading
Loading