diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 7d4162f804..221798f7ab 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,6 @@ ### Fixed +* Fix incorrect `StructLayout(Size = 1)` emission for data-less struct unions where the compiler-generated tag field makes the actual runtime size larger. ([PR #19759](https://github.com/dotnet/fsharp/pull/19759)) * Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776)) * Fix `[]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[]` and `[]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738)) * Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 49207b9f48..aceb8512ca 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -12031,18 +12031,10 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option } let layout = - // Structs with no instance fields get size 1, pack 0 + // Multi-case struct unions carry a hidden tag field; single-case struct unions + // are handled by the CLR's minimum-1-byte guarantee. No explicit size needed. if isStructTy g thisTy then - if - (tycon.AllFieldsArray.Length = 0 - || tycon.AllFieldsArray |> Array.exists (fun f -> not f.IsStatic)) - && (alternatives - |> Array.collect (fun a -> a.FieldDefs) - |> Array.exists (fun fd -> not fd.ILField.IsStatic)) - then - ILTypeDefLayout.Sequential { Size = None; Pack = None } - else - ILTypeDefLayout.Sequential { Size = Some 1; Pack = Some 0us } + ILTypeDefLayout.Sequential { Size = None; Pack = None } else ILTypeDefLayout.Auto diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs index 9314881045..348fc4ba99 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs @@ -397,7 +397,7 @@ module CustomAttributes_Basic = ] [] - let ``StructLayoutAttribute has size=1 for struct DUs with no instance fields`` () = + let ``StructLayoutAttribute doesn't have size=1 for multi-case struct DUs with no instance fields`` () = Fsx """ [] type Option<'T> = None | Some """ @@ -413,8 +413,6 @@ module CustomAttributes_Basic = [runtime]System.IComparable, [runtime]System.Collections.IStructuralComparable { - .pack 0 - .size 1 .custom instance void [FSharp.Core]Microsoft.FSharp.Core.StructAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [runtime]System.Diagnostics.DebuggerDisplayAttribute::.ctor(string) = ( 01 00 15 7B 5F 5F 44 65 62 75 67 44 69 73 70 6C 61 79 28 29 2C 6E 71 7D 00 00 ) @@ -426,4 +424,28 @@ module CustomAttributes_Basic = .field public static literal int32 Some = int32(0x00000001) } """ - ] \ No newline at end of file + ] + + [] + let ``StructLayoutAttribute doesn't have size=1 for single-case struct DU`` () = + Fsx """ + [] type X = | Y + """ + |> compile + |> shouldSucceed + |> verifyIL [ + """ + .class sequential autochar serializable sealed nested public beforefieldinit X + extends [runtime]System.ValueType + implements class [runtime]System.IEquatable`1, + [runtime]System.Collections.IStructuralEquatable, + class [runtime]System.IComparable`1, + [runtime]System.IComparable, + [runtime]System.Collections.IStructuralComparable + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.StructAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerDisplayAttribute::.ctor(string) = ( 01 00 15 7B 5F 5F 44 65 62 75 67 44 69 73 70 6C + 61 79 28 29 2C 6E 71 7D 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 01 00 00 00 00 00 ) + """ + ]