Navigation Menu

Skip to content

Commit

Permalink
[metadata] Fields whose types are gparams with a reference type const…
Browse files Browse the repository at this point in the history
…raint

aren't blittlable.

Don't try to layout the field to find out if it's blittable.

Fixes certain recursive examples.

```
using System;

namespace TestRecursiveType
{
    class Program
    {
        static void Main(string[] args)
        {
            SubClass subC = new SubClass();
            Console.WriteLine(subC.GetTest());
        }
    }

    public struct ValueTest<U>
    {
        // When U is instantiated with T, from BaseClass, we know it'll be a
	// reference field, so we know the instantiation ValueTest<T> won't
	// be blittable.
        public readonly U value;
    }

    public abstract class BaseClass<T> where T : BaseClass<T>
    {
        public ValueTest<T> valueTest = default(ValueTest<T>);
    }

    public class SubClass : BaseClass<SubClass>
    {
        private String test = "test";

        public string GetTest()
        {
            return test;
        }
    }
}
```

Fixes mono#15760
  • Loading branch information
lambdageek committed Jul 19, 2019
1 parent 3ff64f1 commit fe72027
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
37 changes: 37 additions & 0 deletions mono/metadata/class-init.c
Expand Up @@ -3501,6 +3501,41 @@ type_has_references (MonoClass *klass, MonoType *ftype)
return FALSE;
}

static gboolean
mono_class_is_gparam_with_reference_parent (MonoClass *klass)
{
MonoType *type = m_class_get_byval_arg (klass);
g_assert (mono_type_is_generic_parameter (type));
MonoGenericParam *gparam = type->data.generic_param;
if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0)
return TRUE;
if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0)
return FALSE;

/* FIXME: is this reasonable? */
if (mono_generic_param_owner (gparam)->is_anonymous)
return FALSE;

/* We could have: T : U, U : Base. So have to follow the constraints. */
MonoClass *parent_class = mono_generic_param_get_base_type (klass);

g_assert (!MONO_CLASS_IS_INTERFACE_INTERNAL (parent_class));

/* Parent can only be: System.Object, System.ValueType or some specific base class.
*
* If the parent_class is ValueType, the valuetype constraint would be set, above, so
* we wouldn't get here.
*
* If there was a reference constraint, the parent_class would be System.Object,
* but we would have returned early above.
*
* So if we get here, there is either no base class constraint at all,
* in which case parent_class would be set to System.Object, or there is none at all.
*/
return klass->parent != mono_defaults.object_class;

}

/*
* mono_class_layout_fields:
* @class: a class
Expand Down Expand Up @@ -3613,6 +3648,8 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
if (blittable) {
if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
blittable = FALSE;
} else if (mono_type_is_generic_parameter (field->type) && mono_class_is_gparam_with_reference_parent (mono_class_from_mono_type_internal (field->type))) {
blittable = FALSE;
} else {
MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
if (field_class) {
Expand Down
2 changes: 2 additions & 0 deletions mono/metadata/class.c
Expand Up @@ -4028,6 +4028,8 @@ mono_generic_param_get_base_type (MonoClass *klass)

MonoGenericParam *gparam = type->data.generic_param;

g_assert (gparam->owner && !gparam->owner->is_anonymous);

MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;

MonoClass *base_class = mono_defaults.object_class;
Expand Down
10 changes: 9 additions & 1 deletion mono/metadata/metadata.c
Expand Up @@ -7292,6 +7292,12 @@ mono_type_is_pointer (MonoType *type)
(type->type == MONO_TYPE_FNPTR)));
}

static mono_bool
mono_gparam_is_reference (MonoGenericParam *gparam)
{
return (mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
}

/**
* mono_type_is_reference:
* \param type the \c MonoType operated on
Expand All @@ -7304,7 +7310,9 @@ mono_type_is_reference (MonoType *type)
(type->type == MONO_TYPE_SZARRAY) || (type->type == MONO_TYPE_CLASS) ||
(type->type == MONO_TYPE_OBJECT) || (type->type == MONO_TYPE_ARRAY)) ||
((type->type == MONO_TYPE_GENERICINST) &&
!mono_metadata_generic_class_is_valuetype (type->data.generic_class))));
!mono_metadata_generic_class_is_valuetype (type->data.generic_class)) ||
(mono_type_is_generic_parameter (type) &&
mono_gparam_is_reference (type->data.generic_param))));
}

mono_bool
Expand Down

0 comments on commit fe72027

Please sign in to comment.