Skip to content
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

Address warnings for possibly null array elements #41046

Merged
merged 3 commits into from
Aug 20, 2020

Conversation

cston
Copy link
Member

@cston cston commented Aug 19, 2020

As of dotnet/roslyn#46405, the C# compiler considers constraint types for conversions involving type parameter types.

A warning is reported for the following for instance:

#nullable enable

interface I { }

class Program
{
    static void F0<T>(ref T x, ref T y)
    {
    }
    static void F<T>(ref T x, ref T y) where T : I
    {
        if (x == null) { }
        F0(ref x, ref y); // warning: x may be null
    }
}

This results in several new warnings building dotnet/runtime (see dotnet/roslyn#46577).

while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ;
while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) == null) ;
while (Unsafe.IsAddressLessThan(ref leftRef!, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ;
while (Unsafe.IsAddressGreaterThan(ref rightRef!, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) == null) ;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not understanding why the compiler flags this. Why does the compiler think these methods could assign null to the ref?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the warning is for the value of ref argument when the method is called. On the second time through the loop, leftRef is assumed to be null based on && (leftRef = ...) == null.

Copy link
Member

@stephentoub stephentoub Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Is the right fix here then to actually annotate both arguments with [AllowNull]? (That would apply to all members of Unsafe that accept multiple ref Ts and only care about the address, not the actual value, e.g. AreSame, ByteOffset, IsAddressGreaterThan, IsAddressLessThan, and in both the public Unsafe.cs ref as well as the internal implementation in corelib.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the right fix here then to actually annotate both arguments with [AllowNull]?

The methods in Unsafe simply take an unconstrained T which seems like it should be sufficient for all callers. Should the leftRef, etc. locals be declared as ref T? here instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the leftRef, etc. locals be declared as ref T? here instead?

Perhaps not. That would just move the warnings to the initializers of those locals.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the leftRef, etc. locals be declared as ref T? here instead?

Wouldn't that be a problem if a T t; were passed in, with the compiler then complaining that the implementation might assign null to it?

Copy link
Member

@stephentoub stephentoub Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the leftRef, etc. locals be declared as ref T? here instead?

Perhaps not. That would just move the warnings to the initializers of those locals.

Right, hence my question about [AllowNull]. Does that make sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to the Volatile.Read APIs, where ideally we could change ref T to in T, but that would be a breaking API change.

@stephentoub
Copy link
Member

Thanks, @cston. Once this goes in, it should be ported to release/5.0 to unblock updating the compiler there as well. Thanks!
cc: @danmosemsft

@cston
Copy link
Member Author

cston commented Aug 20, 2020

I assume you validated adding the AllowNull does indeed also fix the issue?

Yes, adding [AllowNull] resolved the warnings.

@cston cston merged commit e79f856 into dotnet:master Aug 20, 2020
@safern
Copy link
Member

safern commented Aug 20, 2020

/backport to release/5.0

@github-actions
Copy link
Contributor

Started backporting to release/5.0: https://github.com/dotnet/runtime/actions/runs/217132032

@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants