# C# Language Design Meeting for April 1st, 2026

## Agenda

- [Unsafe evolution migration and explicit safety markers](#unsafe-evolution-migration-and-explicit-safety-markers)
    - [Marking `extern` members as explicitly safe](#marking-extern-members-as-explicitly-safe)
    - [Avoiding easy but incorrect unsafe evolution migration paths](#avoiding-easy-but-incorrect-unsafe-evolution-migration-paths)

## Quote of the Day

- "We could ask them which character they think their child thinks they are"

## Discussion

### Unsafe evolution migration and explicit safety markers

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Spec: https://github.com/dotnet/csharplang/blob/7d432c0b3cae3c775e0ac055c3b70085c895b315/proposals/unsafe-evolution.md  
PR reviewed: https://github.com/dotnet/csharplang/pull/10051/changes/7d432c0b3cae3c775e0ac055c3b70085c895b315  
Working group notes: https://github.com/dotnet/csharplang/blob/7d432c0b3cae3c775e0ac055c3b70085c895b315/meetings/working-groups/unsafe-evolution/missing-safety-marker.md  
Working group notes: https://github.com/dotnet/csharplang/blob/7d432c0b3cae3c775e0ac055c3b70085c895b315/meetings/working-groups/unsafe-evolution/unsafe-mod-mar.md  
Working group notes: https://github.com/dotnet/csharplang/blob/7d432c0b3cae3c775e0ac055c3b70085c895b315/meetings/working-groups/unsafe-evolution/incremental-unsafe.md  
Working group notes: https://github.com/dotnet/csharplang/blob/7d432c0b3cae3c775e0ac055c3b70085c895b315/meetings/working-groups/unsafe-evolution/unsafe-evolution-compatibility-proposal.md

Today we reviewed gaps found while trying to apply the unsafe evolution model to real codebases, including ongoing runtime
adoption work.

We focused on a tension between two failure modes: making suppression too easy, which hides real memory-safety
responsibilities, or making adoption too hard, which leads users to bypass the model instead of correctly annotating code.
We compared this to early `async` adoption, where broad mechanical annotation created substantial follow-on correctness
problems when developers marked everything quickly without preserving intended semantics.

#### Marking `extern` members as explicitly safe

The first major gap we discussed concerned `extern` members. The current default treatment of `extern` as caller-unsafe is
sound, but it is too rigid for cases where an `extern` boundary does not actually impose additional caller obligations. We
revisited whether the language should support an explicit way to affirm that a specific member is caller-safe.

We considered several syntax shapes in principle, including attribute-based and keyword-based forms. The central design
concern was not surface syntax, but whether the language has a clear and auditable mechanism for expressing that an
`extern` member has been reviewed and does not propagate unsafety to callers.

A related point was that broad suppressions remain undesirable. We viewed marking at type scope as especially problematic,
because it acts as a future attestation for methods added later, rather than a localized justification near the actual
unsafe operation.

#### Avoiding easy but incorrect unsafe evolution migration paths

The second major gap was migration behavior from existing unsafe semantics to unsafe evolution semantics. We discussed how
existing broad `unsafe` usage can suppress diagnostics that would otherwise force users to align with unsafe evolution
rules. This can produce a dangerous outcome where code compiles cleanly after opt-in but has not actually been audited
under the new model.

We emphasized that pointer-containing signatures and coarse `unsafe` usage often appear valid during migration even when
they do not meet unsafe evolution intent. More generally, we stressed that an "enabled with no diagnostics" outcome is not
an acceptable success criterion for existing unsafe code.

We also discussed concerns about migration affordances that are too attractive but semantically shallow. Any annotation
mechanism should push users toward explicit, reviewable decisions, rather than creating a low-friction path that silences
diagnostics without a corresponding safety audit.

#### Conclusion

There was overwhelming agreement that the language needs a way for users to mark a member as explicitly "safe", whatever
syntax is ultimately chosen.

We also tentatively supported requiring certain member categories, such as `extern` members, to carry an explicit "safe"
or "unsafe" marker, rather than allowing an unmarked default in those cases.
