Better check for intermediate value modifications. Fixes #6763
authorMarek Safar <marek.safar@gmail.com>
Tue, 4 Sep 2012 07:03:50 +0000 (09:03 +0200)
committerMarek Safar <marek.safar@gmail.com>
Tue, 4 Sep 2012 07:04:42 +0000 (09:04 +0200)
mcs/errors/cs1612-9.cs [new file with mode: 0644]
mcs/mcs/ecore.cs
mcs/mcs/expression.cs

diff --git a/mcs/errors/cs1612-9.cs b/mcs/errors/cs1612-9.cs
new file mode 100644 (file)
index 0000000..d9b0f65
--- /dev/null
@@ -0,0 +1,21 @@
+// CS1612: Cannot modify a value type return value of `R.Size'. Consider storing the value in a temporary variable
+// Line: 19
+
+struct R
+{
+       public S Size { get; set; }
+}
+
+struct S
+{
+       public float Height { get; set; }
+}
+
+public class Test
+{
+       public static void Main ()
+       {
+               var r = new R ();
+               r.Size.Height = 3;
+       }
+}
index a5e86a1d8ba8585dff1c180726da52b34bf4fc36..22fa0cacd60bcd3b1bf1b7e16b0fb15351f90055 100644 (file)
@@ -323,14 +323,7 @@ namespace Mono.CSharp {
                public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
                {
                        if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
-                               rc.Report.SymbolRelatedToPreviousError (type);
-                               if (rc.CurrentInitializerVariable != null) {
-                                       rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
-                                               type.GetSignatureForError (), GetSignatureForError ());
-                               } else {
-                                       rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
-                                               GetSignatureForError ());
-                               }
+                               // Already reported as CS1612
                        } else {
                                rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
                        }
@@ -2942,6 +2935,30 @@ namespace Mono.CSharp {
                }
 
                public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
+               {
+                       if (!ResolveInstanceExpressionCore (rc, rhs))
+                               return false;
+
+                       //
+                       // Check intermediate value modification which won't have any effect
+                       //
+                       if (rhs != null && InstanceExpression.Type.IsStruct &&
+                               (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
+
+                               if (rc.CurrentInitializerVariable != null) {
+                                       rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
+                                               InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
+                               } else {
+                                       rc.Report.Error (1612, loc,
+                                               "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
+                                               InstanceExpression.GetSignatureForError ());
+                               }
+                       }
+
+                       return true;
+               }
+
+               bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
                {
                        if (IsStatic) {
                                if (InstanceExpression != null) {
@@ -3005,7 +3022,7 @@ namespace Mono.CSharp {
 
                        var me = InstanceExpression as MemberExpr;
                        if (me != null) {
-                               me.ResolveInstanceExpression (rc, rhs);
+                               me.ResolveInstanceExpressionCore (rc, rhs);
 
                                // Using this check to detect probing instance expression resolve
                                if (!rc.OmitStructFlowAnalysis) {
@@ -6079,11 +6096,6 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       // if the property/indexer returns a value type, and we try to set a field in it
-                       if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
-                               Error_ValueAssignment (ec, right_side);
-                       }
-
                        if (eclass == ExprClass.Unresolved) {
                                var expr = OverloadResolve (ec, right_side);
                                if (expr == null)
index d401547c158335eda7125afdbaa8b213f087c581..95dd9e1a19b1f31b4fe896d39d1d172f4622531b 100644 (file)
@@ -8540,11 +8540,6 @@ namespace Mono.CSharp
                        if (res == null)
                                return null;
 
-                       bool lvalue_instance = rhs != null && type.IsStruct && (Expr is Invocation || Expr is PropertyExpr);
-                       if (lvalue_instance) {
-                               Expr.Error_ValueAssignment (ec, EmptyExpression.LValueMemberAccess);
-                       }
-
                        return res.ResolveLValue (ec, rhs);
                }