-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
There are some confusing diagnostics where "feature is not supported in C# 12" is reported but if you upgrade to C# 13, you get an error "pointers must be used in unsafe context". It would be better if the latter error has been reported in C# 12 as well. This happens because unsafe/safe contexts changed slightly between C# 12 and 13, so in C# 12 the compiler thinks we are in unsafe context and you just need to upgrade to C# 13, but in C# 13 we are suddenly in safe context, so you get the unsafe error. For example:
unsafe class C
{
System.Collections.Generic.IEnumerable<int> M()
{
int* p = null; // langversion error in C# 12; unsafe error in C# 13
yield break;
}
}
Similarly, there can be errors in C# 12 saying a construct (e.g., await or pointer) is not supported in an unsafe context. But if you upgrade to C# 13, that feature works since the context becomes safe. It would be better if we reported a langversion error in C# 12 (i.e., error saying "feature is not supported in C# 12", so users know they can just upgrade to make the error scenario work). For example:
unsafe class C
{
System.Collections.Generic.IEnumerable<int> M()
{
var lam = () => sizeof(nint); // unsafe error in C# 12; works in C# 13
yield break;
}
}
Lastly, there are some unnecessary diagnostics in C# 12 where you get an error for every unsafe construct in an unsafe block inside an iterator even though you already got that error for the unsafe block itself, so the nested errors are just noise. Note that this is a preexisting behavior, only previously the errors said "cannot use unsafe in iterators" and now they say "unsafe in iterators is not supported in C# 12". They disappear completely in C# 13. Still, we could filter them out in C# 12, but that is tricky because we do not know if we are inside an unsafe block in an iterator (see M1
below) or if the unsafe context is just inherited from parent (in which case we cannot filter out the errors; see M2
below). For example:
unsafe class C
{
System.Collections.Generic.IEnumerable<int> M1()
{
unsafe // langversion error in C# 12
{
int* p; // unnecessary langversion error in C# 12
}
yield break;
}
System.Collections.Generic.IEnumerable<int> M2()
{
int* p; // necessary langversion error in C# 12
yield break;
}
}
All of these could be solved by e.g., having separate BinderFlags for "unsafe region in C# 12" and "unsafe region in C# 13" that we could use in the compiler to decide which diagnostics to report. However, BinderFlags is uint
currently and does not have any free slots.
Note: this issue will be referenced in tests (via #73046).
Related to #72662.