Suppress CS3016 on internal COM wrappers without [CLSCompliant(false)] (#1703)#1723
Merged
jevansaks merged 1 commit intoJun 12, 2026
Merged
Conversation
microsoft#1703) The microsoft#1703 fix marked CCW-bearing COM struct wrappers [CLSCompliant(false)] to silence CS3016 (a Roslyn limitation that flags array-valued [UnmanagedCallersOnly] attribute arguments even on non-visible types, dotnet/roslyn#68526). That type-level attribute induces CS3019/CS3021, which Roslyn reports against the type *symbol* — so when a consumer adds their own friendly-helper partial to a generated COM struct (e.g. dotnet/winforms System.Private.Windows.Core's ITypeInfo.cs), the diagnostic lands on the consumer's file and escapes the generated file's pragma. Result: CS3021 (no assembly CLSCompliant attribute) or CS3019 (assembly is CLS-compliant) breaks the consumer build under TreatWarningsAsErrors. Fix: stop emitting [CLSCompliant(false)] entirely. Instead suppress CS3016 directly in the generated file's header pragma, where the offending thunk lives. CS3016 is reported at the thunk method (always in our generated file), so the file-scoped pragma silences it precisely without masking user code, and because no attribute is emitted, CS3019/CS3021 can never arise regardless of consumer partials or assembly CLS posture. The suppression is applied only to internal projections (the default). Public projections do not get it: a public COM interop surface is the consumer's CLS contract to own (and is inherently non-CLS-compliant anyway), so CsWin32 must not unilaterally silence it. Removes the now-unused CLSCompliantFalse() factory and the CS3019/CS3021 entries from the generated-file pragma. Adds regression coverage: the internal cross-TFM x assembly-CLS matrix, public-projection omits-suppression, friendly-helper-partial with and without an assembly CLSCompliant attribute, and a load-bearing test proving CS3016 still fires when the pragma is stripped.
jevansaks
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the dotnet/winforms#14639 fallout from #1703: a consumer that adds a friendly-helper
partialto a generated CCW-bearing COM struct (e.g.System.Private.Windows.Core'sITypeInfo.cs) now builds clean.#1703 marked CCW-bearing COM struct wrappers
[CLSCompliant(false)]to silence CS3016 (a Roslyn limitation that flags the array-valued[UnmanagedCallersOnly(CallConvs = new[]{...})]thunk argument even on non-visible types — dotnet/roslyn#68526). But that type-level attribute induces CS3019/CS3021, which Roslyn reports against the type symbol. When a consumer adds their own partial to the struct, the diagnostic lands on the consumer''s file and escapes the generated file''s pragma:[assembly: CLSCompliant]->CS3021[assembly: CLSCompliant(true)]->CS3019Under
TreatWarningsAsErrorsthis breaks the consumer build.Fix
Stop emitting
[CLSCompliant(false)]. Instead suppress CS3016 directly in the generated file''s header pragma, where the offending thunk lives:Removes the now-unused
CLSCompliantFalse()factory and theCS3019/CS3021entries from the generated-file pragma.Tests
net472/net10.0) x assembly-CLS-posture matrix asserting no CS3016/CS3019/CS3021.[CLSCompliant]).[CLSCompliant]attribute (the winforms#14639 shape).Validated end-to-end with a real
net472;net10.0cross-compile consuming the locally-built generator.