# C# Language Design Meeting for April 22nd, 2026

## Agenda

- [Unsafe evolution, continued](#unsafe-evolution-continued)
    - [Signature `unsafe` and unsafe contexts](#signature-unsafe-and-unsafe-contexts)
    - [Transitional diagnostics for pointer-signature calls](#transitional-diagnostics-for-pointer-signature-calls)

## Quote(s) of the Day

- "Sooner or later we'll have the tick in C#" ... "I interpreted that as The Tick from the comics"
- "That broke my brain"
- "I know this is like pulling teeth, but at the end of it we will have a complete design" "We have teeth left?" "We're sharks, we have many teeth."

## Discussion

### Unsafe evolution, continued

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Spec: https://github.com/dotnet/csharplang/blob/a9445cbaa27a5b8569567fc35940bf1ea6923c65/proposals/unsafe-evolution.md  
Working group notes: https://github.com/dotnet/csharplang/blob/a9445cbaa27a5b8569567fc35940bf1ea6923c65/meetings/working-groups/unsafe-evolution/unsafe-simple-core-model.md

Continuing from [our previous discussion](./LDM-2026-04-13.md#unsafe-evolution-continued), we returned to
unsafe evolution to settle two important design questions. First, we reexamined whether `unsafe` on a member
should continue to make the whole member body an unsafe context, or whether that outward-facing contract
should be separated from the local lexical regions where actual unsafe operations occur. Second, we looked at
the temporary "dip" created by making most pointer operations safe before the ecosystem has fully opted in
to the new model.

#### Signature `unsafe` and unsafe contexts

We started by revisiting a premise from the recent simple core model: that `unsafe` on a member both marks
the member as caller-unsafe and also places the entire body in an unsafe context. The main objection was
that this makes caller-unsafe members fundamentally different from caller-safe members with internal unsafe
implementation details. In the latter case, authors can localize the risky operations with small `unsafe`
blocks. In the former, the whole method becomes one large unsafe region whether or not that reflects the
actual audit boundary they want to communicate.

That asymmetry no longer felt justified. If the goal of unsafe evolution is to make review obligations
clearer, then it is helpful for authors to be able to scope the truly unsafe operations explicitly even
inside members that propagate an audit obligation to callers. We also noted that, as a matter of language
design taste, it is cleaner when a modifier on the signature describes the member's contract and a block in
the body describes the actual lexical unsafe region. A separate outward-facing keyword was briefly floated,
but we did not want to complicate the design with additional syntax before settling the semantics.

##### Conclusion

For unsafe evolution, we will separate these concepts: `unsafe` on a member will no longer automatically
make the whole body an unsafe context. Instead, under the new rules, only explicit `unsafe` regions in the
body will establish an unsafe context for operations that require it.

#### Transitional diagnostics for pointer-signature calls

We then returned to the migration problem we have been calling the "dip". Under unsafe evolution, most uses
of pointer types become safe regardless of opt-in, which creates a temporary window where existing code can
become less protected before libraries and callers have fully moved to the new caller-unsafe model. In the
common case today, methods with pointer types in their signatures are already being called from within
unsafe contexts, and we did not want that requirement to disappear simply because the language rules are in
transition.

The room was not trying to produce a fully principled long-term rule here. This is a transitional safeguard
meant to keep the current ecosystem from silently becoming more permissive in the most obviously risky
cases. We discussed several follow-on questions that still need more work, including whether the same rule
should also apply across opted-in and non-opted-in boundaries, and whether the resulting diagnostic should
ultimately be an error or a warning. For today, we aimed for the narrowest decision that preserves the old
protection where it matters most.

##### Conclusion

We will give diagnostics for calls made outside an unsafe context from non-opted-in code to non-opted-in
members whose signatures contain pointers. The exact shape and severity of those diagnostics, and whether
they should extend to other caller/callee combinations, remains for future discussion.
