# C# Language Design Meeting for January 26th, 2026

## Agenda

- [Alternative syntax for caller-unsafe](#alternative-syntax-for-caller-unsafe)

## Quote(s) of the Day

- "[redacted], you are the most punctual person ever. You joined exactly when the clock hit [meeting start time]. Are you using some kind of auto-meeting joiner?" "No, I was just watching the clock."
- "ų̷n̷s̷a̷f̷e̷"
- "That wasn't a particularly bad dad joke, was it? It wasn't quote of the day material." "Well that was"

## Discussion

### Alternative syntax for caller-unsafe

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Spec: https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/proposals/unsafe-evolution.md  
Working group notes: https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/meetings/working-groups/unsafe-evolution/unsafe-alternative-syntax.md

Continuing from [last week's discussion](./LDM-2026-01-21.md), the LDM had a strong lean toward not repurposing the
existing `unsafe` keyword for caller-unsafe semantics. Today we explored the remaining design space: should we use an
attribute like `[RequiresUnsafe]`, or a new keyword other than `unsafe`?

Several arguments were raised in favor of an attribute approach. An attribute is a safer incremental choice; we could
ship an attribute, learn from user feedback during the .NET 11 preview cycle, and add a keyword later if needed. We
cannot remove a keyword once introduced. Attributes also provide more flexibility for distinguishing between existing
members that became caller-unsafe (where consumers may need an escape hatch during migration) versus new members that
are caller-unsafe from the start (where there's no conceptual reason to allow opting out).

On the other hand, strong arguments were made for a dedicated keyword. A keyword conveys the seriousness with which C#
is treating memory safety and makes it a first-class language concept. If caller-unsafe were just an attribute, it
would be effectively the same as shipping an analyzer; it wouldn't feel like part of the language. The signal value
matters: as the industry increasingly demands memory-safe languages, C# needs to demonstrate that safety is built into
the language itself, not bolted on as an afterthought.

The discussion also touched on audit ergonomics. The guidance that the libraries team is working on is to keep `unsafe`
blocks as small as possible, drawing the eye to precisely where unsafety occurs. This has implications for the syntax
design: having both `unsafe` at the method level and `[RequiresUnsafe]` on the same member is effectively incorrect,
you probably never want both. When `unsafe` is at the method level, it suppresses all warnings internally, making it
impossible to audit which specific operations are unsafe. This means that when users enable the feature, they cannot
easily audit their existing code; they would need to go through every usage of `unsafe` line by line. Or, we have to
make the breaking change even larger, and change `unsafe` on a member to not create an `unsafe` block inside the member
at all. This is currently an active question in the proposal, but if we proceed with `unsafe` as the keyword, then we
would need to answer that question.

We then brainstormed extensively on possible syntaxes:

1. `[RequiresUnsafe]`
2. `[CallerUnsafe]`
3. `[Requires("unsafe")]`, `[Requires("experimental")]`
4. `callerunsafe`
5. `requiresunsafe`
6. `unsafe(caller)`
7. `requires(unsafe)`
8. `requires unsafe`
9. `unsafe required`
10. `#require unsafe`
11. `requires-unsafe`
12. `unsafe-caller`
13. `modifier(unsafe)`
14. `unprotected`
15. `dangerous`
16. `access unsafe`
17. `[RequiresUnsafeContext]`
18. `propagate unsafe`
19. `unsafe(propagate)`
20. `[UnsafeOnly]`
21. `leakunsafe`
22. `exportunsafe`

After an initial round of voting, the options were narrowed down to `[RequiresUnsafe]`, `[CallerUnsafe]`,
`requiresunsafe`, `unsafe(caller)`, `requires unsafe`, and `unsafe required`. A second round of voting further narrowed
the field to `[RequiresUnsafe]`, `[CallerUnsafe]`, `[UnsafeOnly]`, `requires unsafe`, `unsafe(caller)`, and
`requiresunsafe`. None of the keyword options were liked by a majority of the LDM, with most preferring the attribute
approach, with `[RequiresUnsafe]` being the preferred option. We then compared this against the original proposal:
repurposing `unsafe` itself. `[RequiresUnsafe]` is preferred over repurposing the `unsafe` keyword, so we will proceed
with the alternative syntax proposal.

#### Conclusion

We will use an attribute, `[RequiresUnsafe]`, for communicating when the caller of a method or user of a field/property
must be in an `unsafe` context.
