-
Notifications
You must be signed in to change notification settings - Fork 1.1k
More unsafe spec updates
#9831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
More unsafe spec updates
#9831
Conversation
Add a few more open questions and adjust the wording with decisions from the [12th](https://github.com/dotnet/csharplang/blob/5d9c7bec7677a6ce335652712b9fe483680ef487/meetings/2025/LDM-2025-11-12.md).
proposals/unsafe-evolution.md
Outdated
| is updated to include whether the _anonymous function_ has the `unsafe` keyword, or the _method group_ is to a member that is marked `unsafe`. If it is, an anonymous function type is created, just as | ||
| it would be if any parameter were a by-`ref`, optional, or `params`. | ||
|
|
||
| It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this include object as well? Otherwise, one can do unsafe delegate -> object -> safe delegate.
What can one actually do with the unsafe delegates with all these limitations? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What can one actually do with the unsafe delegates with all these limitations?
Pass them around and call them in an unsafe context. I don't know how much people are generally counting on converting them object or similar; I certainly don't use that functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, pass them around on your little island. I do not expect libraries are generally going to have APIs that take unsafe delegate arguments.
To me, it feels like that the unsafe delegates are a mine field that will require a lot of special casing and provide very little value. Starting without them may be better.
| ### Delegate type `unsafe`ty | ||
|
|
||
| We could remove the ability to make delegate types as `unsafe` entirely, and simply require that all conversions of `unsafe` lambdas or method groups to a delegate type occur inside an `unsafe` context. | ||
| This could simplify the model around `unsafe` in C#, but at the risk of forcing `unsafe` annotations in the wrong spot and having an area where the real area of `unsafe`ty isn't properly called out. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we started without unsafe delegates, can they be added later as an incremental non-breaking change once/if proven necessary? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I expect so.
| it would be if any parameter were a by-`ref`, optional, or `params`. | ||
|
|
||
| It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`. | ||
| It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`, or any interface those |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean that the unsafe delegates cannot be used as generic arguments (in safe contexts)?
If they can be used as generic arguments, one can do the offending memory unsafe cast indirectly by doing e..g.:
IEnumerable<UnsafeDelegate> e1 = ...!;
IEnumerable<Delegate> e2 = e1.Cast<Delegate>();
| > [!NOTE] | ||
| > We don't actually attribute the delegate type itself, just the `Invoke`, `BeginInvoke`, and `EndInvoke` methods. Determining whether a delegate type is `unsafe` is done by examining those 3 methods. | ||
| > If all are marked as `unsafe`, the delegate type is considered `unsafe`. If only some are marked as `unsafe`, then it is presumed that calling the others is safe and only calling the member that is | ||
| > marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that is does not have all of `Invoke`, `BeginInvoke`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| > marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that is does not have all of `Invoke`, `BeginInvoke`, | |
| > marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that does not have all of `Invoke`, `BeginInvoke`, |
| member bodies of that type are considered an `unsafe` context. `unsafe` on a member will mean that that member is `unsafe`, and the body of that member is considered an `unsafe` context. For existing code | ||
| moving to the new definition of `unsafe`, this may produce a number of false positives for methods that don't need to be considered `unsafe`; we believe this better than false positives around not doing | ||
| this, or making it an error to put `unsafe` on a type which would easily be the largest breaking change that we've ever introduced in C#. | ||
| (except for iterator bodies). We propose changing this definition from textual to sematic. `unsafe` on a member will mean that that member is `unsafe`, and the body of that member is considered an `unsafe` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the syntactical meaning of unsafe on bodies, there is no change, right? So for example, iterators still escape out of the unsafe context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an open question on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an open question on that.
|
|
||
| ### Lambda/method group natural types | ||
|
|
||
| Today, the only real impact on codegen (besides additional metadata) is changing the *function_type* of a lambda or method group when `unsafe` is in the signature. If we were to avoid doing this, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not impacting just codegen, it's impacting semantics too since different delegate types cannot be converted to each other, so for example this snippet will stop working:
unsafe void M() { }
var x = M;
System.Action y = x;
Add a few more open questions and adjust the wording with decisions from the 12th.