Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@jkoritzinsky
Copy link
Member

@jkoritzinsky jkoritzinsky commented May 28, 2025

The interop team has decided to add a new mechanism to specify type layouts, designed similarly to how the UnmanagedCallersOnly feature was designed. In particular, the team has decided to use the last remaining value in the "Layout Kind" mask of a type def's attributes to represent "extended layout". When this value it set, the runtime will look for the System.Runtime.InteropServices.ExtendedLayoutAttribute to provide all layout information.

As part of the design process, we noticed that Roslyn blocks emitting a type with the last remaining value of the System.Runtime.InteropServices.LayoutKind enumeration in the StructLayout pseudo-attribute as the compiler can't map it to a valid TypeAttributes value.
 
The System.Runtime.InteropServices.ExtendedLayoutAttribute type was approved in dotnet/runtime#100896 and has the first part of runtime implementation (the TypeAttributes bit and the LayoutKind value) in dotnet/runtime#116082.

The support in C# is to allow the user to specify the ExtendedLayoutAttribute on a type. When they do so, the correct layout bit will be set. The user cannot manually specify the new "extended layout" value. The only way in C# to specify that value is to put this attribute on the type.

The ExtendedLayoutAttribute will be embedded in NoPia scenarios as the layout bits are embedded in NoPia scenarios.

This should go into .NET 11

@jkoritzinsky jkoritzinsky requested a review from a team as a code owner May 28, 2025 23:50
@jaredpar
Copy link
Member

@jkoritzinsky think we'll need a small specification document for this contribution.

@jkoritzinsky
Copy link
Member Author

I'll put one together. Where is the best place for it to go?

@jaredpar
Copy link
Member

I'll put one together. Where is the best place for it to go?

dotnet/csharplang. @333fred can you think of a good example that would be similar to this?

@jkoritzinsky
Copy link
Member Author

I considered doing a proposal in csharplang, but there's zero specifications of StructLayoutAttribute or FieldOffset on csharplang or csharpstandard.

@333fred
Copy link
Member

333fred commented May 29, 2025

I would agree with Jeremy, C# the language doesn't care about those attributes, just Roslyn the compiler. Perhaps under docs/features? Also, what support does VB have for these attributes, and what will we need to update in its support?

@jaredpar
Copy link
Member

Hmm ... for some reason I thought the spec discussed StructLayout but looking now it does not. Let's just drop a spec doc/features then.

@jkoritzinsky
Copy link
Member Author

I'll drop a spec in docs/features and add VB support.

@jkoritzinsky
Copy link
Member Author

I've added a spec and added VB support

…nch 'main' of github.com:dotnet/roslyn into extended-layout
@333fred
Copy link
Member

333fred commented Dec 18, 2025

This is generally looking ok to me. @dotnet/roslyn-compiler for a second review.

@jcouv jcouv self-assigned this Dec 19, 2025
// System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor
(byte)MemberFlags.Constructor, // Flags
(byte)WellKnownType.System_Runtime_CompilerServices_AsyncStateMachineAttribute, // DeclaringTypeId
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_AsyncStateMachineAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId// DeclaringTypeId
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// DeclaringTypeId

duplicated // DeclaringTypeId #Closed

(byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Threading_Tasks_Task_T,
1,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
// System_Runtime_InteropServices_ExtendedLayoutAttribute__ctor
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider also adding a line break above #Closed

}

if (containingType.HasStructLayoutAttribute || containingType.HasInlineArrayAttribute(out _))
if (containingType.HasStructLayoutAttribute || containingType.HasExtendedLayoutAttribute || containingType.HasInlineArrayAttribute(out _))
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's another usage of HasStructLayoutAttribute below at line 2768. Should it also be updated? #Closed

return default(TypeLayout);

default:
if ((def.Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExtendedLayout)
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtendedLayout is emitted as an attribute, unlike StructLayout, We should decide what to do when the extended flag and the [ExtendedLayout(...)] attribute don't agree, in metadata.
I couldn't find any place where the compiler cares about the value from Layout from metadata, outside of verifying that the information round-trips through metadata. Is there any other scenario where it matters?
In any case, let's add a test (you can use CreateCompilationWithIL).

Btw, do we have a test observing that ExtendedLayout attribute is emitted? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no other case that Roslyn cares about the Layout metadata. I'll add some IL tests to validate behavior when the attribute and the metadata bits disagree.

CreateEmptyCompilation(
source,
references: [s_extendedLayoutAttributeMinimalCoreLibrary])
.VerifyDiagnostics(
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use VerifyEmitDiagnostics for all tests that error. It pulls a bit further in the compilation pipeline and we sometimes find issues with later pipeline phases that have trouble dealing with unexpected configuration of symbols. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no VerifyEmitDiagnostics when using CompileAndVerify. It looks like VerifyDiagnostics on the CompilationVerifier looks at the emit diagnostics though. Is that okay?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. If you just create a compilation and verify diagnostics, then use VerifyEmitDiagnostics. If you use CompileAndVerify (which already emits) then use VerifyDiagnostics on that.

CreateEmptyCompilation(
source,
references: [s_extendedLayoutAttributeMinimalCoreLibrary])
.VerifyDiagnostics(
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also verify what the symbols report in this error scenario #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried moving this to use CompileAndVerify, but because it has error diagnostics, it fails to emit. I'm going to write this as Assert calls on top of the returned compilation, ok? Or is there another way I should do this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you can get symbols from the compilation. var comp = CreateCompiation(...); var e = comp.GlobalNamespace.GetTypeMember("E"); ... assert on e ...


If HasExtendedLayoutAttribute And Not ContainingAssembly.RuntimeSupportsExtendedLayout Then
diagnostics = BindingDiagnosticBag.GetInstance()
diagnostics.Add(ERRID.ERR_RuntimeDoesNotSupportExtendedLayoutTypes, GetFirstLocation(), Me)
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a test for this in VB? Found it: ExtendedLayoutAttribute_DefinedInOtherAssembly_Errors #Closed

If diagnostics Is Nothing Then
diagnostics = BindingDiagnosticBag.GetInstance()
End If
diagnostics.Add(ERRID.ERR_StructLayoutAndExtendedLayout, GetFirstLocation())
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a test for this in VB? Found it: ExtendedLayout_OtherLayoutKind_Errors #Closed

If Me.IsGenericType Then
diagnostics.Add(ERRID.ERR_StructLayoutAttributeNotAllowed, arguments.AttributeSyntaxOpt.GetLocation(), Me)
End If
ElseIf attrData.IsTargetAttribute(AttributeDescription.ExtendedLayoutAttribute) Then
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StructLayout appears disallowed on generic types (a few lines above). Should the same restriction apply to ExtendedLayout? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a VB-only restriction, C# does not block it. Additionally, I think that that restriction is both not necessary for ExtendedLayout and would block key scenarios if we did it across the board. If we wanted to block it just for VB though, I personally don't really care one way or the other. I don't expect anyone to use this from VB.

Structure C
~
]]>)
End Sub
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a test for partial types in VB? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no warning from the VB compiler when partial members are split across types for types that are explicitly LayoutKind.Sequential, so I didn't add the same feature for extended layout (and as a result did not add a test for partials). I can add one if you'd like just to validate the metadata.

To provide the user experience requested by the runtime team, the C# and VB compilers will have the following support for this attribute:

- If a type has the `ExtendedLayoutAttribute` applied, the compiler will emit the `TypeAttributes.ExtendedLayout` value in the type's `TypeAttributes` flags.
- If a type has the `ExtendedLayoutAttribute` applied, the compiler will not allow the `StructLayoutAttribute` to be applied to the type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR: The linked API proposal wasn't updated to clarify that ExtendedLayout attribute implies StructLayout(Extended). The code samples still show explicit [StructLayout(Extended)].

@@ -0,0 +1,16 @@
System.Runtime.InteropServices.ExtendedLayoutAttribute Compiler Support
Copy link
Member

@jcouv jcouv Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR: will the F# compiler need to be updated as well? Consider filing an issue #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F# issue opened as well: dotnet/fsharp#19190

F# shouldn't need any changes to consume, but it will need changes to correctly produce types with the right bits set.

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with review pass (commit 28)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks (commit 30) modulo unnecessary using

@jkoritzinsky jkoritzinsky enabled auto-merge (squash) January 6, 2026 20:17
@jkoritzinsky jkoritzinsky merged commit 85d6c4a into dotnet:main Jan 6, 2026
24 of 25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C# compiler integration with new System.Runtime.InteropServices.ExtendedLayoutAttribute

5 participants