# C# Language Design Meeting for May 27th, 2026

## Agenda

- [Unsafe evolution](#unsafe-evolution)
    - [Unsafe expressions](#unsafe-expressions)
    - [Await in unsafe blocks](#await-in-unsafe-blocks)
    - [Safety comments](#safety-comments)

## Quote(s) of the Day

- "The mic died again"
- "I love that I can see the curse words, even without sound."

## Discussion

### Unsafe evolution

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Spec: https://github.com/dotnet/csharplang/blob/d2372c220b36e2abe60348b46d963ce470bdb824/proposals/unsafe-evolution.md#unsafe-expressions

We started by looking at a gap in the unsafe evolution proposal that showed up as the runtime team started experimenting
with analyzers to migrate code from the current `unsafe` model to the proposed model. The goal of the migration is to move
`unsafe` inward: instead of marking an entire method as `unsafe`, code should generally put `unsafe` around the operation
that actually requires a manual safety audit. In several expression contexts, however, that is either awkward or impossible
with only `unsafe` statements.

#### Unsafe expressions

The proposed solution was to add an `unsafe` expression form, analogous to `checked` and `unchecked` expressions. The
expression would establish an `unsafe` context for the expression it contains, and the value and type of the `unsafe`
expression would be the value and type of that inner expression.

The most immediate motivation is that some expressions cannot be wrapped in an `unsafe` statement without changing the
shape of the surrounding code. Examples included field initializers, constructor initializers, and nested calls such as
passing the result of a *requires-unsafe* call directly as an argument to another method. Without an expression form, users
would often need to introduce temporary locals or helper methods purely to create a statement-shaped location for an
`unsafe` block. That makes the migration noisier, can obscure which operation is actually unsafe, and in async cases can
force less direct code shapes.

There was broad support for the feature. We liked the symmetry with `checked` and `unchecked`, and the fact that a single
expression form addresses several otherwise unrelated syntactic holes. We also noted that this syntax should be available
unconditionally in the next language version, rather than being gated on opting in to the updated memory safety rules. That
keeps the migration path open: users can rewrite code into the new shape before enabling the stricter rules.

One concern was that adding an expression form creates a style choice between `unsafe` expressions and `unsafe` statements.
Some codebases may prefer to keep `unsafe` regions as statement blocks except where an expression is necessary. We did not
think that style question should block the language feature. It is similar to existing choices between checked expressions
and checked statements, and guidance can steer authors toward readable code without preventing the expression form.

##### Conclusion

We will add `unsafe` expressions.

#### Await in unsafe blocks

The same migration work also exposed an existing restriction: `await` cannot appear inside an `unsafe` block. That
restriction becomes more visible under unsafe evolution because the new model encourages moving `unsafe` inward into method
bodies, including async methods. We discussed whether to pursue removing or narrowing that restriction.

The original reason for the restriction appears to have been concern about hoisting unsafe state into async state machines,
particularly pointers to stack locations. Under the new model, however, pointer types themselves are no longer inherently
unsafe. That means simply disallowing `await` inside an `unsafe` block no longer fully captures the cases we care about:
there will be code involving pointers and awaits that is syntactically outside an `unsafe` block, and there are also uses of
`unsafe` blocks that do not involve pointers at all.

We discussed whether the existing warning for taking the address of locals or parameters in async methods is already the
right kind of protection for some of the concerning cases. We also noted that `fixed` blocks and pinning pointers need a
clear answer. One likely direction is to continue disallowing `await` inside a `fixed` block, but that needs to be written
down as part of a concrete proposal rather than inferred from today's broad discussion.

The room generally thought that relaxing the blanket `await` restriction is worth pursuing, but not as an immediate decision
from this meeting. The right question is broader than a single syntactic restriction: we need a proposed model for how
`unsafe`, async lowering, pointers, and pinning interact in the updated memory-safety world.

##### Conclusion

The working group will produce a concrete proposal for relaxing or replacing the current restriction on `await` inside
`unsafe` blocks and bring it back to LDM.

#### Safety comments

Working group notes: https://github.com/dotnet/csharplang/blob/33be130d1bf59a177911a38ed89d8756106a627a/meetings/working-groups/unsafe-evolution/safety-comments.md

Finally, we discussed a working group proposal for safety comments. The motivating idea is that the `unsafe` keyword
is only part of the end-to-end story. If a method is marked `unsafe`, then callers have obligations that the compiler and
runtime cannot check for them. Those obligations need to be stated somewhere that callers, reviewers, auditors, and tools can
find. Without that documentation, the burden shifts from the API author to every consumer or auditor of the API.

The proposal was informed by Rust and Swift practices. Rust in particular has a convention for a public safety section on
unsafe APIs and local safety comments near unsafe operations. The proposed C# shape was similar: an outer documentation
comment tag for obligations that an `unsafe` member pushes to callers, and an inner comment convention for explaining how a
body discharges obligations when it performs unsafe operations. The proposal also suggested a warning when an `unsafe` member
lacks the outer safety documentation, likely when the updated memory safety rules are enabled.

We separated two different questions. The first is whether public documentation for caller obligations should have a
recognized `safety` form and whether the toolchain should warn when it is missing. There was general support for this. A
warning, rather than an error, seemed important because generated interop bindings and similar code may not be able to author
complete safety documentation directly, and because C# already treats documentation diagnostics as warnings that projects can
configure.

The second question is what to do with inner comments that explain why a particular unsafe operation is valid. Several people
liked the idea of using the same XML documentation-comment form both outside and inside method bodies, rather than having
outer `/// <safety>` comments and inner `// SAFETY:` comments as two different syntactic conventions. A unified form could
reuse existing doc-comment tooling, including richer references and formatting. Others noted that inner comments are more of
a code-review convention than a contract exposed to callers, and that the compiler may not need to validate or even
understand them to ship the unsafe evolution feature.

We also discussed whether this belongs in the language, an analyzer, the SDK, or broader platform guidance. There is a
tension between treating safety documentation as a language-recognized part of the `unsafe` contract and treating it as an
ecosystem convention enforced by tooling. From the user's perspective, either compiler diagnostics or SDK analyzers can show
up as warnings when a project opts into the relevant platform defaults, but the implementation choice affects flexibility,
configuration, and how closely this is tied to existing documentation-comment behavior.

The conversation ended without a concrete decision. We leaned toward wanting a safety documentation tag for `unsafe` members,
but we need to better understand how it should interact with existing documentation-comment parsing and diagnostics, what the
default warning behavior should be, and whether inner safety comments should be specified, merely recommended, or left to
project-specific style.
