Bug 14906 - GENERICS: Taking a pointer to a T qualified as struct now fails. (recent breakage)
Summary: GENERICS: Taking a pointer to a T qualified as struct now fails. (recent br...
Alias: None
Product: Compilers
Classification: Mono
Component: C# ()
Version: unspecified
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: ---
Assignee: Marek Safar
Depends on:
Reported: 2013-09-21 19:27 UTC by Brian Berry
Modified: 2013-09-22 11:12 UTC (History)
1 user (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Brian Berry 2013-09-21 19:27:02 UTC
Found:  A recent alpha channel update (this week?) resulted in breakage of previously functioning code of the form:

    public static unsafe void Foo<T>(T[] data) where T : struct
        fixed (T* t = &data[0])
            // Do stuff.

The pattern above now results in "Cannot take the address of, get the size of, or declare a pointer to a managed type T" errors, which you would normally see had the T not been qualified with the "where T : struct" portion.

Expected: So long as a T is qualified as struct (value type), the above pattern continues to work.

NOTE: The non-generic cases still work as expected.  E.g., the following results in the same error indicated above:

    public class MyType
        int a;

    public static unsafe void Foo(MyType[] data)
        fixed (MyType* t = &data[0])
            // Do stuff.

...yet the above block does *not* result in an error if the class is changed to a struct.

This appears to have been a recent change to the behavior of generics, has the symptom that the "where T : struct" is no longer being honored?

Unfortunately, we are having to specialize our previously-functioning generics all over the codebase (much duplication) in order to be able to continue to compile/run in this condition.

Many thanks!
Comment 1 Brian Berry 2013-09-21 19:30:22 UTC
Forgot to add:

Xamarin Studio
Version 4.1.11 (build 10)
Installation UUID: b577b744-52dd-4f14-848b-8dcc8a961c91
	Mono 3.2.3 ((no/8d3b4b7)
Comment 2 Marek Safar 2013-09-22 08:42:16 UTC
The code violates C# spec so the error is correct.

It depends what you need to achieve but you can use something like this instead

var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject();
// free handle later
Comment 3 Brian Berry 2013-09-22 10:30:39 UTC
Thanks for the quick response, Marek.

I'll take a look at the spec a little closer.  I installed a copy of MSVS (had been using Xamarin Studio exclusively to date) and found the same results.

It remains an academic curiosity to me why, though, the spec (or at least the current compilers) would allow fixed blocks to acquire pointers to arrays of concrete structs, while at the same time disallow the same in the generic case even if the Ts are constrained to structs.   You are, in essence, telling the compiler that the type is constrained to that which it *would* allow had you simply typed it concretely yourself.   Generics are supposed to help us reduce that typing.

If I am missing something you can shed light on (e.g. a struct case that would be illegal that the generic has to protect against), I'd love to hear it.  (But don't go out of your way, just curious.)

I will look into the alternatives.

Thanks again.
Comment 4 Brian Berry 2013-09-22 11:12:29 UTC
Just a quick followup/conclusion.  Indeed, the generic case qualified as struct does not fully guarantee a legal struct, as all struct members must also be of unmanaged types.   Thus compilers have to disallow the pattern.