From: Marek Safar Date: Tue, 3 Oct 2017 13:27:11 +0000 (+0200) Subject: [mcs] Implements C# 7.2 readonly structs X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=1004d95b6b70e8b67a2b6782e0832faab9fa269a [mcs] Implements C# 7.2 readonly structs --- diff --git a/mcs/errors/cs0106-11.cs b/mcs/errors/cs0106-11.cs new file mode 100644 index 00000000000..9aa99e36bc6 --- /dev/null +++ b/mcs/errors/cs0106-11.cs @@ -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 index 00000000000..fa2cfd27dae --- /dev/null +++ b/mcs/errors/cs0459-5.cs @@ -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 index 00000000000..7116ba3dafa --- /dev/null +++ b/mcs/errors/cs1604-2.cs @@ -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 index 00000000000..738899bfe4f --- /dev/null +++ b/mcs/errors/cs1605-2.cs @@ -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 index 00000000000..de713efba4d --- /dev/null +++ b/mcs/errors/cs1644-56.cs @@ -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 diff --git a/mcs/errors/cs8145.cs b/mcs/errors/cs8145.cs index cf3c5084722..ffbadfd67df 100644 --- a/mcs/errors/cs8145.cs +++ b/mcs/errors/cs8145.cs @@ -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 index 00000000000..9236e9468b8 --- /dev/null +++ b/mcs/errors/cs8340-2.cs @@ -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 index 00000000000..fb3376708b2 --- /dev/null +++ b/mcs/errors/cs8340.cs @@ -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 index 00000000000..c78406345fe --- /dev/null +++ b/mcs/errors/cs8341.cs @@ -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 index 00000000000..d6d7f43f0bf --- /dev/null +++ b/mcs/errors/cs8342.cs @@ -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 diff --git a/mcs/mcs/attribute.cs b/mcs/mcs/attribute.cs index ca142609003..3ff2d68ccb5 100644 --- a/mcs/mcs/attribute.cs +++ b/mcs/mcs/attribute.cs @@ -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 | diff --git a/mcs/mcs/class.cs b/mcs/mcs/class.cs index 07bf45f12ef..9afb32c6fe5 100644 --- a/mcs/mcs/class.cs +++ b/mcs/mcs/class.cs @@ -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 (); diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index 648effd7f10..6e20a8b13f0 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -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) $10); + if ($9 != null) + current_container.SetConstraints ((List) $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 (); } diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 3407b9faf88..89207a3b54a 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -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) diff --git a/mcs/mcs/field.cs b/mcs/mcs/field.cs index da337a8261a..86bb028defc 100644 --- a/mcs/mcs/field.cs +++ b/mcs/mcs/field.cs @@ -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) diff --git a/mcs/mcs/import.cs b/mcs/mcs/import.cs index 719ba23952c..1cddf7c01f4 100644 --- a/mcs/mcs/import.cs +++ b/mcs/mcs/import.cs @@ -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; } } diff --git a/mcs/mcs/property.cs b/mcs/mcs/property.cs index 3478711470a..c55432cf2d5 100644 --- a/mcs/mcs/property.cs +++ b/mcs/mcs/property.cs @@ -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; diff --git a/mcs/mcs/typespec.cs b/mcs/mcs/typespec.cs index 0585dfd667a..d14e1ead3e3 100644 --- a/mcs/mcs/typespec.cs +++ b/mcs/mcs/typespec.cs @@ -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 index 00000000000..7cce9e0d600 --- /dev/null +++ b/mcs/tests/test-readonly-01.cs @@ -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 diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index 16a62d1ce87..636afd18a00 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -72668,6 +72668,25 @@ + + + + 40 + + + 40 + + + 13 + + + 7 + + + 2 + + +