[mcs] Implements C# 7.2 readonly structs
authorMarek Safar <marek.safar@gmail.com>
Tue, 3 Oct 2017 13:27:11 +0000 (15:27 +0200)
committerMarek Safar <marek.safar@gmail.com>
Tue, 3 Oct 2017 15:01:58 +0000 (17:01 +0200)
20 files changed:
mcs/errors/cs0106-11.cs [new file with mode: 0644]
mcs/errors/cs0459-5.cs [new file with mode: 0644]
mcs/errors/cs1604-2.cs [new file with mode: 0644]
mcs/errors/cs1605-2.cs [new file with mode: 0644]
mcs/errors/cs1644-56.cs [new file with mode: 0644]
mcs/errors/cs8145.cs
mcs/errors/cs8340-2.cs [new file with mode: 0644]
mcs/errors/cs8340.cs [new file with mode: 0644]
mcs/errors/cs8341.cs [new file with mode: 0644]
mcs/errors/cs8342.cs [new file with mode: 0644]
mcs/mcs/attribute.cs
mcs/mcs/class.cs
mcs/mcs/cs-parser.jay
mcs/mcs/expression.cs
mcs/mcs/field.cs
mcs/mcs/import.cs
mcs/mcs/property.cs
mcs/mcs/typespec.cs
mcs/tests/test-readonly-01.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

diff --git a/mcs/errors/cs0106-11.cs b/mcs/errors/cs0106-11.cs
new file mode 100644 (file)
index 0000000..9aa99e3
--- /dev/null
@@ -0,0 +1,7 @@
+// CS0106: The modifier `readonly' is not valid for this item
+// Line: 6
+// Compiler option: -langversion:latest
+
+readonly interface I
+{
+}
diff --git a/mcs/errors/cs0459-5.cs b/mcs/errors/cs0459-5.cs
new file mode 100644 (file)
index 0000000..fa2cfd2
--- /dev/null
@@ -0,0 +1,13 @@
+// CS0459: Cannot take the address of `this' because it is read-only
+// Line: 11
+// Compiler options: -unsafe -langversion:latest
+
+readonly struct X
+{
+       unsafe void Test ()
+       {
+               fixed (X* x = &this) {
+
+               }
+       }
+}
diff --git a/mcs/errors/cs1604-2.cs b/mcs/errors/cs1604-2.cs
new file mode 100644 (file)
index 0000000..7116ba3
--- /dev/null
@@ -0,0 +1,11 @@
+// CS1604: Cannot assign to `this' because it is read-only
+// Line: 8
+// Compiler options: -langversion:latest
+
+readonly struct S
+{
+       void Foo ()
+       {
+               this = new S ();
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs1605-2.cs b/mcs/errors/cs1605-2.cs
new file mode 100644 (file)
index 0000000..738899b
--- /dev/null
@@ -0,0 +1,16 @@
+// CS1605: Cannot pass `this' as a ref or out argument because it is read-only
+// Line: 14
+// Compiler options: -langversion:latest
+
+readonly struct X
+{
+       void Test (out X x)
+       {
+               x = new X ();
+       }
+       
+       void Run ()
+       {
+               Test (out this);
+       }
+}
diff --git a/mcs/errors/cs1644-56.cs b/mcs/errors/cs1644-56.cs
new file mode 100644 (file)
index 0000000..de713ef
--- /dev/null
@@ -0,0 +1,7 @@
+// CS1644: Feature `readonly structs' cannot be used because it is not part of the C# 7.0 language specification
+// Line: 5
+// Compiler options: -langversion:7
+
+readonly struct S
+{
+}
\ No newline at end of file
index cf3c50847224a78513e2cfdb19b1eb2c90633182..ffbadfd67df2e8900bb36995ca2e5ede02d62f6d 100644 (file)
@@ -1,4 +1,4 @@
-// CS8145: Auto-implemented properties cannot return by reference
+// CS8145: Auto-implemented property `X.TestProp' cannot return by reference
 // Line: 6
 
 public class X
diff --git a/mcs/errors/cs8340-2.cs b/mcs/errors/cs8340-2.cs
new file mode 100644 (file)
index 0000000..9236e94
--- /dev/null
@@ -0,0 +1,13 @@
+// CS8340: `S.field': Instance fields in readonly structs must be readonly
+// Line: 6
+// Compiler options: -langversion:latest
+
+readonly partial struct S
+{
+
+}
+
+partial struct S
+{
+       int field;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8340.cs b/mcs/errors/cs8340.cs
new file mode 100644 (file)
index 0000000..fb33767
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8340: `S.field': Instance fields in readonly structs must be readonly
+// Line: 6
+// Compiler options: -langversion:latest
+
+readonly struct S
+{
+       int field;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8341.cs b/mcs/errors/cs8341.cs
new file mode 100644 (file)
index 0000000..c784063
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8341: Auto-implemented instance property `S.field' in readonly structs must be readonly
+// Line: 6
+// Compiler options: -langversion:latest
+
+readonly struct S
+{
+       int field { get; set; }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8342.cs b/mcs/errors/cs8342.cs
new file mode 100644 (file)
index 0000000..d6d7f43
--- /dev/null
@@ -0,0 +1,10 @@
+// CS8342: `S.e': Field-like instance events are not allowed in readonly structs
+// Line: 6
+// Compiler options: -langversion:latest
+
+using System;
+
+readonly struct S
+{
+       event Action e;
+}
\ No newline at end of file
index ca142609003dc480033ea2ae6be3e5182266453d..3ff2d68ccb5ad38964c23c0890f4372c9a4406ef 100644 (file)
@@ -1755,6 +1755,9 @@ namespace Mono.CSharp {
                // New in .NET 4.7
                public readonly PredefinedTupleElementNamesAttribute TupleElementNames;
 
+               // New in .NET 4.7.1
+               public readonly PredefinedAttribute IsReadOnly;
+
                //
                // Optional types which are used as types and for member lookup
                //
@@ -1835,6 +1838,7 @@ namespace Mono.CSharp {
                        CallerFilePathAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerFilePathAttribute");
 
                        TupleElementNames = new PredefinedTupleElementNamesAttribute (module, "System.Runtime.CompilerServices", "TupleElementNamesAttribute");
+                       IsReadOnly = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IsReadOnlyAttribute");
 
                        // TODO: Should define only attributes which are used for comparison
                        const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
index 07bf45f12ef73f8e0a8527053f96bb599948793e..9afb32c6fe5677d71cdd7632d08c79a43302e040 100644 (file)
@@ -3022,7 +3022,8 @@ namespace Mono.CSharp
                        Modifiers.PROTECTED |
                        Modifiers.INTERNAL  |
                        Modifiers.UNSAFE    |
-                       Modifiers.PRIVATE;
+                       Modifiers.PRIVATE   |
+                       Modifiers.READONLY;
 
                public Struct (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
                        : base (parent, name, attrs, MemberKind.Struct)
@@ -3135,6 +3136,9 @@ namespace Mono.CSharp
 
                public override void Emit ()
                {
+                       if ((ModFlags & Modifiers.READONLY) != 0)
+                               Module.PredefinedAttributes.IsReadOnly.EmitAttribute (TypeBuilder);
+
                        CheckStructCycles ();
 
                        base.Emit ();
index 648effd7f1095c7731e5ed6797a6bd3ceb20dd3e..6e20a8b13f0aeedac01b0a29afcb61722a4b34c1 100644 (file)
@@ -1020,13 +1020,16 @@ struct_declaration
          opt_modifiers
          opt_partial
          STRUCT
-         {
-         }
          type_declaration_name
-         { 
+         {
+               var mods = (Modifiers) $2;
+               if ((mods & Modifiers.READONLY) != 0 && lang_version < LanguageVersion.V_7_2) {
+                       FeatureIsNotAvailable (GetLocation ($4), "readonly structs");
+               }
+
                lexer.ConstraintsParsing = true;
                valid_param_mod = ParameterModifierType.PrimaryConstructor;
-               push_current_container (new Struct (current_container, (MemberName) $6, (Modifiers) $2, (Attributes) $1), $3);
+               push_current_container (new Struct (current_container, (MemberName) $5, mods, (Attributes) $1), $3);
          }
          opt_primary_parameters
          opt_class_base
@@ -1035,11 +1038,11 @@ struct_declaration
                valid_param_mod = 0;
                lexer.ConstraintsParsing = false;
 
-               if ($8 != null)
-                       current_type.PrimaryConstructorParameters = (ParametersCompiled) $8;
+               if ($7 != null)
+                       current_type.PrimaryConstructorParameters = (ParametersCompiled) $7;
 
-               if ($10 != null)
-                       current_container.SetConstraints ((List<Constraints>) $10);
+               if ($9 != null)
+                       current_container.SetConstraints ((List<Constraints>) $9);
 
                if (doc_support)
                        current_container.PartialContainer.DocComment = Lexer.consume_doc_comment ();
@@ -1061,10 +1064,10 @@ struct_declaration
          }
          opt_semicolon
          {
-               if ($16 == null) {
-                       lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15));
+               if ($15 == null) {
+                       lbag.AppendToMember (current_container, GetLocation ($11), GetLocation ($14));
                } else {
-                       lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15), GetLocation ($17));
+                       lbag.AppendToMember (current_container, GetLocation ($11), GetLocation ($14), GetLocation ($16));
                }
                $$ = pop_current_class ();
          }
index 3407b9faf884118562ea008f55c838c4b5d885bd..89207a3b54a26868eeadd5b13ed7110a4e9f768e 100644 (file)
@@ -9005,7 +9005,7 @@ namespace Mono.CSharp
                        if (eclass == ExprClass.Unresolved)
                                ResolveBase (ec);
 
-                       if (type.IsClass){
+                       if (type.IsClass || type.IsReadOnly) {
                                if (right_side == EmptyExpression.UnaryAddress)
                                        ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
                                else if (right_side == EmptyExpression.OutAccess)
index da337a8261ab40ed86f89ad0d63b53e2aec3c2cc..86bb028defcb766e3d46d3ff6bed497962cb470b 100644 (file)
@@ -700,6 +700,16 @@ namespace Mono.CSharp
                        return true;
                }
 
+               protected override void DoMemberTypeIndependentChecks ()
+               {
+                       if ((Parent.PartialContainer.ModFlags & Modifiers.READONLY) != 0 && (ModFlags & (Modifiers.READONLY | Modifiers.STATIC)) == 0) {
+                               Report.Error (8340, Location, "`{0}': Instance fields in readonly structs must be readonly",
+                                       GetSignatureForError ());
+                       }
+
+                       base.DoMemberTypeIndependentChecks ();
+               }
+
                protected override void DoMemberTypeDependentChecks ()
                {
                        if ((ModFlags & Modifiers.BACKING_FIELD) != 0)
index 719ba23952cd714f0021ef68335b081af7a94640..1cddf7c01f4b8478f80c0a158e47a25a1b688873 100644 (file)
@@ -959,7 +959,8 @@ namespace Mono.CSharp
                                        }
                                }
 
-                               if (kind == MemberKind.Class) {
+                               switch (kind) {
+                               case MemberKind.Class:
                                        if ((ma & TypeAttributes.Sealed) != 0) {
                                                if ((ma & TypeAttributes.Abstract) != 0)
                                                        mod |= Modifiers.STATIC;
@@ -968,6 +969,13 @@ namespace Mono.CSharp
                                        } else if ((ma & TypeAttributes.Abstract) != 0) {
                                                mod |= Modifiers.ABSTRACT;
                                        }
+                                       break;
+                               case MemberKind.Struct:
+                                       if (HasAttribute (CustomAttributeData.GetCustomAttributes (type), "IsReadOnlyAttribute", CompilerServicesNamespace)) {
+                                               mod |= Modifiers.READONLY;
+                                       }
+
+                                       break;
                                }
                        }
 
index 3478711470a0fa6d93b668621c5d60392e2fda08..c55432cf2d59171c7b4a9e3576a418ec8b12c300 100644 (file)
@@ -880,10 +880,16 @@ namespace Mono.CSharp
                                }
 
                                if (MemberType.Kind == MemberKind.ByRef) {
-                                       Report.Error (8145, Location, "Auto-implemented properties cannot return by reference");
+                                       Report.Error (8145, Location, "Auto-implemented property `{0}' cannot return by reference",
+                                               GetSignatureForError ());
                                        return false;
                                }
 
+                               if ((Parent.PartialContainer.ModFlags & Modifiers.READONLY) != 0 && Set != null && !IsStatic) {
+                                       Report.Error (8341, Location, "Auto-implemented instance property `{0}' in readonly structs must be readonly",
+                                               GetSignatureForError ());
+                               }
+
                                if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
                                        Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");
 
@@ -1191,6 +1197,16 @@ namespace Mono.CSharp
                        base.ApplyAttributeBuilder (a, ctor, cdata, pa);
                }
 
+               protected override void DoMemberTypeIndependentChecks ()
+               {
+                       if ((Parent.PartialContainer.ModFlags & Modifiers.READONLY) != 0 && (ModFlags & Modifiers.STATIC) == 0) {
+                               Report.Error (8342, Location, "`{0}': Field-like instance events are not allowed in readonly structs",
+                                       GetSignatureForError ());
+                       }
+
+                       base.DoMemberTypeIndependentChecks ();
+               }
+
                public override bool Define()
                {
                        var mod_flags_src = ModFlags;
index 0585dfd667a08d6d7f56cf247831eb915fbb7d49..d14e1ead3e317c07b55873ca2e679a7d6d3205a9 100644 (file)
@@ -237,6 +237,8 @@ namespace Mono.CSharp
                        }
                }
 
+               public bool IsReadOnly => (modifiers & Modifiers.READONLY) != 0;
+
                //
                // Returns true for instances of any System.ValueTuple<......> type
                //
diff --git a/mcs/tests/test-readonly-01.cs b/mcs/tests/test-readonly-01.cs
new file mode 100644 (file)
index 0000000..7cce9e0
--- /dev/null
@@ -0,0 +1,16 @@
+// Compiler options: -langversion:latest
+
+using System;
+
+readonly struct S
+{
+       readonly int field;
+
+       static int sf;
+       static event Action e;
+       static int Prop { get; set; }
+
+       public static void Main ()
+       {
+       }
+}
\ No newline at end of file
index 16a62d1ce87d50337879aadbe40bed7a49913d54..636afd18a008618d542007d52c3a340bb8697323 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-readonly-01.cs">
+    <type name="S">
+      <method name="Void add_e(System.Action)" attrs="2193">
+        <size>40</size>
+      </method>
+      <method name="Void remove_e(System.Action)" attrs="2193">
+        <size>40</size>
+      </method>
+      <method name="Int32 get_Prop()" attrs="2193">
+        <size>13</size>
+      </method>
+      <method name="Void set_Prop(Int32)" attrs="2193">
+        <size>7</size>
+      </method>
+      <method name="Void Main()" attrs="150">
+        <size>2</size>
+      </method>
+    </type>
+  </test>
   <test name="test-ref-01.cs">
     <type name="X">
       <method name="Void Main()" attrs="150">