--- /dev/null
+// CS0131: The left-hand side of an assignment must be a variable, a property or an indexer
+// Line: 8
+
+class X
+{
+ void Test ()
+ {
+ Foo () = 1;
+ }
+
+ static int Foo ()
+ {
+ return 1;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0199: A static readonly field `X.f' cannot be passed ref or out (except in a static constructor)
+// Line: 10
+
+class X
+{
+ static readonly int f = 0;
+
+ public static void Main ()
+ {
+ ref int j = ref f;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0206: A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter
+// Line: 10
+
+class X
+{
+ static int P { get; set; }
+
+ static void Main ()
+ {
+ ref int rl = ref P;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1503: Argument `#1' cannot convert `ref long' expression to type `ref int'
+// Line: 18
+
+using System;
+
+class X
+{
+ long field;
+
+ static void Main ()
+ {
+ var x = new X ();
+ x.Run ();
+ }
+
+ void Run ()
+ {
+ Test (ref Prop);
+ }
+
+ static int Test (ref int y)
+ {
+ return y;
+ }
+
+ ref long Prop {
+ get {
+ return ref field;
+ }
+ }
+}
--- /dev/null
+// CS1547: Keyword `void' cannot be used in this context
+// Line: 6
+
+interface IA
+{
+ ref void Foo ();
+}
--- /dev/null
+// CS1644: Feature `byref locals and returns' cannot be used because it is not part of the C# 6.0 language specification
+// Line: 9
+// Compiler options: -langversion:6
+
+class Text
+{
+ static ref long Foo ()
+ {
+ throw new System.NotImplementedException ();
+ }
+}
--- /dev/null
+// CS1715: `B.Foo': type must be `int' to match overridden member `A.Foo'
+// Line: 11
+
+public abstract class A
+{
+ public abstract ref int Foo { get; }
+}
+
+public class B : A
+{
+ public override ref long Foo {
+ get {
+ throw null;
+ }
+ }
+}
\ No newline at end of file
-// CS1764: Cannot use fixed local `p' inside an anonymous method, lambda expression or query expression
+// CS1764: Cannot use fixed variable `p' inside an anonymous method, lambda expression or query expression
// Line: 10
// Compiler options: -unsafe
--- /dev/null
+// CS8145: Auto-implemented properties cannot return by reference
+// Line: 6
+
+public class X
+{
+ ref string TestProp { get; }
+}
\ No newline at end of file
--- /dev/null
+// CS8146: `X.TestProp': property and indexer which return by reference must have a get accessor
+// Line: 6
+
+public class X
+{
+ ref string TestProp { set; }
+}
\ No newline at end of file
--- /dev/null
+// CS8147: `X.this[int]': property and indexer which return by reference cannot have set accessors
+// Line: 6
+
+public class X
+{
+ ref string this [int arg] {
+ set {
+
+ }
+ get {
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8147: `X.TestProp': property and indexer which return by reference cannot have set accessors
+// Line: 6
+
+public class X
+{
+ ref string TestProp {
+ set {
+
+ }
+ get {
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8148: `B.Foo': must return by reference to match overridden member `A.Foo'
+// Line: 11
+
+public abstract class A
+{
+ public abstract ref int Foo { get; }
+}
+
+public class B : A
+{
+ public override long Foo {
+ get {
+ throw null;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8148: `B.Foo()': must not return by reference to match overridden member `A.Foo()'
+// Line: 11
+
+public abstract class A
+{
+ public abstract int Foo ();
+}
+
+public class B : A
+{
+ public override ref int Foo ()
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8149: By-reference returns can only be used in lambda expressions that return by reference
+// Line: 12
+
+using System;
+
+class A
+{
+ int p;
+
+ void Test ()
+ {
+ Action a = () => ref p;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8149: By-reference returns can only be used in methods that return by reference
+// Line: 10
+
+class A
+{
+ int p;
+
+ int Test ()
+ {
+ return ref p;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8150: By-reference return is required when method returns by reference
+// Line: 10
+
+class A
+{
+ int p;
+
+ ref int Test ()
+ {
+ return p;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8151: The return by reference expression must be of type `string' because this method returns by reference
+// Line: 10
+
+public class X
+{
+ int field;
+
+ ref string TestMethod ()
+ {
+ return ref field;
+ }
+}
--- /dev/null
+// CS8152: `C' does not implement interface member `IA.Foo()' and the best implementing candidate `C.Foo()' return type `void' does not return by reference
+// Line: 11
+
+interface IA
+{
+ ref char Foo ();
+}
+
+public class C : IA
+{
+ public void Foo ()
+ {
+ }
+}
--- /dev/null
+// CS8153: An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference
+// Line: 11
+
+using System;
+using System.Linq.Expressions;
+
+class X
+{
+ void Foo ()
+ {
+ Expression<Func<int>> e = () => Test (ref this[0]);
+ }
+
+ static int Test (ref int y)
+ {
+ return y;
+ }
+
+ ref int this [int y] {
+ get {
+ throw null;
+ }
+ }
+}
--- /dev/null
+// CS8154: The body of `TestClass.TestFunction()' cannot be an iterator block because the method returns by reference
+// Line: 10
+
+class TestClass
+{
+ int x;
+
+ ref int TestFunction()
+ {
+ yield return x;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8155: Lambda expressions that return by reference cannot be converted to expression trees
+// Line: 14
+
+using System.Linq.Expressions;
+
+class TestClass
+{
+ static int x;
+
+ delegate ref int D ();
+
+ static void Main ()
+ {
+ Expression<D> e = () => ref x;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8156: An expression cannot be used in this context because it may not be returned by reference
+// Line: 8
+
+class X
+{
+ int Prop {
+ get {
+ return 1;
+ }
+ }
+
+ ref int Test ()
+ {
+ return ref Prop;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8156: An expression cannot be used in this context because it may not be returned by reference
+// Line: 8
+
+class Test
+{
+ ref int Foo ()
+ {
+ return ref 2;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8157: Cannot return `r' by reference because it was initialized to a value that cannot be returned by reference
+// Line: 11
+
+struct S
+{
+ int i;
+
+ ref int M ()
+ {
+ ref int r = ref i;
+ return ref r;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8160: A readonly field cannot be returned by reference
+// Line: 10
+
+class X
+{
+ readonly int f = 0;
+
+ ref int Test ()
+ {
+ return ref f;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8161: A static readonly field cannot be returned by reference
+// Line: 10
+
+class X
+{
+ static readonly int f;
+
+ static ref int Test ()
+ {
+ return ref f;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8170:
+// Line: 10
+
+public struct S
+{
+ int f;
+
+ public ref S Foo ()
+ {
+ return ref f;
+ }
+}
--- /dev/null
+// CS8170:
+// Line: 8
+
+public struct S
+{
+ public ref S Foo ()
+ {
+ return ref this;
+ }
+}
--- /dev/null
+// CS8171: Cannot initialize a by-value variable `l' with a reference expression
+// Line: 10
+
+class Test
+{
+ int field;
+
+ void Foo ()
+ {
+ int l = ref field;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8172: Cannot initialize a by-reference variable `j' with a value
+// Line: 10
+
+class X
+{
+ static int f;
+
+ public static void Main ()
+ {
+ ref int j = f;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8173: The expression must be of type `long' because it is being assigned by reference
+// Line: 11
+
+public class X
+{
+ int field;
+
+ public static void Main ()
+ {
+ int i = 5;
+ ref long j = ref i;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8174: A declaration of a by-reference variable must have an initializer
+// Line: 8
+
+class X
+{
+ public static void Main ()
+ {
+ ref int j;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8175: Cannot use by-reference variable `v' inside an anonymous method, lambda expression, or query expression
+// Line: 14
+
+using System;
+
+public class Test
+{
+ public static void Main()
+ {
+ var arr = new int [1];
+ ref var v = ref arr [0];
+
+ Action a = delegate {
+ ref var v2 = ref v;
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8176: Iterators cannot use by-reference variables
+// Line: 12
+
+using System.Collections.Generic;
+
+class X
+{
+ int x;
+
+ IEnumerable<int> Test ()
+ {
+ ref int y = ref x;
+ yield break;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8177: Async methods cannot use by-reference variables
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+ int x;
+
+ async Task Test ()
+ {
+ ref int y = ref x;
+ await Task.Yield ();
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8178: `await' cannot be used in an expression containing a call to `X.this[int]' because it returns by reference
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+ int x;
+
+ async Task Test ()
+ {
+ Foo (ref this [await Task.FromResult (1)]);
+ }
+
+ ref int this [int arg] => ref x;
+
+ static void Foo (ref int arg)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8178: `await' cannot be used in an expression containing a call to `X.Wrap(int)' because it returns by reference
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+ int x;
+
+ async Task Test ()
+ {
+ Foo (ref Wrap (await Task.FromResult (1))) = 4;
+ }
+
+ ref int Wrap (int arg)
+ {
+ return ref x;
+ }
+
+ static ref int Foo (ref int arg)
+ {
+ return ref arg;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8189: By reference return delegate does not match `C.D()' return type
+// Line: 15
+
+class C
+{
+ delegate ref int D ();
+
+ static int M ()
+ {
+ return 1;
+ }
+
+ static void Main ()
+ {
+ D d = new D (M);
+ }
+}
\ No newline at end of file
cs8141.cs
cs8141-2.cs
cs8144.cs
+cs8157.cs NO ERROR
+cs8160.cs
+cs8161.cs
+cs8170.cs NO ERROR
+cs8170-2.cs
return Clone (Expr.Clone (clonectx));
}
- public virtual Expression CreateExpressionTree (ResolveContext ec)
+ public virtual Expression CreateExpressionTree (ResolveContext rc)
{
+ if (Type.Kind == MemberKind.ByRef) {
+ rc.Report.Error (8153, Expr.Location, "An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference");
+ return null;
+ }
+
if (ArgType == AType.Default)
- ec.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
+ rc.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
- return Expr.CreateExpressionTree (ec);
+ return Expr.CreateExpressionTree (rc);
}
return;
}
+ if (Expr.Type.Kind == MemberKind.ByRef) {
+ Expr.Emit (ec);
+ return;
+ }
+
AddressOp mode = AddressOp.Store;
if (ArgType == AType.Ref)
mode |= AddressOp.Load;
- IMemoryLocation ml = (IMemoryLocation) Expr;
- ml.AddressOf (ec, mode);
+ ((IMemoryLocation)Expr).AddressOf (ec, mode);
}
public Argument EmitToField (EmitContext ec, bool cloneResult)
return all;
}
- public static Arguments CreateForExpressionTree (ResolveContext ec, Arguments args, params Expression[] e)
+ public static Arguments CreateForExpressionTree (ResolveContext rc, Arguments args, params Expression[] e)
{
Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
for (int i = 0; i < e.Length; ++i) {
- if (e [i] != null)
- all.Add (new Argument (e[i]));
+ var expr = e [i];
+ if (expr != null) {
+ all.Add (new Argument (expr));
+ }
}
if (args != null) {
foreach (Argument a in args.args) {
- Expression tree_arg = a.CreateExpressionTree (ec);
+ Expression tree_arg = a.CreateExpressionTree (rc);
if (tree_arg != null)
all.Add (new Argument (tree_arg));
}
var base_member_type = ((IInterfaceMemberSpec)base_member).MemberType;
if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) {
Report.SymbolRelatedToPreviousError (base_member);
- if (this is PropertyBasedMember) {
+ if (((base_member_type.Kind ^ MemberType.Kind) & MemberKind.ByRef) != 0) {
+ Report.Error (8148, Location, "`{0}': must {2}return by reference to match overridden member `{1}'",
+ GetSignatureForError (), base_member.GetSignatureForError (), base_member_type.Kind == MemberKind.ByRef ? "" : "not ");
+ } else if (this is PropertyBasedMember) {
Report.Error (1715, Location, "`{0}': type must be `{1}' to match overridden member `{2}'",
GetSignatureForError (), base_member_type.GetSignatureForError (), base_member.GetSignatureForError ());
} else {
return null;
}
+ if (expr is ReferenceExpression) {
+ // Only identify conversion is allowed
+ return null;
+ }
+
e = ImplicitNumericConversion (expr, expr_type, target_type);
if (e != null)
return e;
field_declaration
: opt_attributes
opt_modifiers
- member_type IDENTIFIER
+ ref_member_type IDENTIFIER
{
lexer.parsing_generic_declaration = false;
}
;
+ref_member_type
+ : member_type
+ {
+ $$ = $1;
+ }
+ | REF
+ {
+ lexer.parsing_generic_declaration = true;
+ }
+ type
+ {
+ if (lang_version < LanguageVersion.V_7) {
+ FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+ }
+
+ $$ = new ReferenceTypeExpr ((FullNamedExpression) $3, GetLocation ($1));
+ }
+ ;
+
method_header
: opt_attributes
opt_modifiers
- member_type
+ ref_member_type
method_declaration_name OPEN_PARENS
{
valid_param_mod = ParameterModifierType.All;
}
| opt_attributes
opt_modifiers
- member_type
+ ref_member_type
modifiers method_declaration_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
{
MemberName name = (MemberName) $5;
}
| opt_attributes
opt_modifiers
- member_type
+ ref_member_type
method_declaration_name error
{
Error_SyntaxError (yyToken);
++lexer.parsing_block;
start_block (GetLocation ($1));
}
- expression SEMICOLON
+ lambda_arrow_expression SEMICOLON
{
lexer.parsing_block = 0;
current_block.AddStatement (new ContextualReturn ((Expression) $3));
property_declaration
: opt_attributes
opt_modifiers
- member_type
+ ref_member_type
member_declaration_name
{
lexer.parsing_generic_declaration = false;
if (doc_support)
current_property.DocComment = ConsumeStoredComment ();
+
+ if ($3 is ReferenceTypeExpr) {
+ if (current_property.Get == null) {
+ report.Error (8146, GetLocation ($4), "`{0}': property and indexer which return by reference must have a get accessor", current_property.GetSignatureForError ());
+ }
+
+ if (current_property.Set != null) {
+ report.Error (8147, GetLocation ($4), "`{0}': property and indexer which return by reference cannot have set accessors", current_property.GetSignatureForError ());
+ }
+ }
}
CLOSE_BRACE
{
}
| opt_attributes
opt_modifiers
- member_type
+ ref_member_type
member_declaration_name
{
lexer.parsing_generic_declaration = false;
indexer_declaration
: opt_attributes opt_modifiers
- member_type indexer_declaration_name OPEN_BRACKET
+ ref_member_type indexer_declaration_name OPEN_BRACKET
{
valid_param_mod = ParameterModifierType.Params | ParameterModifierType.DefaultValue;
}
if (doc_support)
current_property.DocComment = ConsumeStoredComment ();
+
+ if ($3 is ReferenceTypeExpr) {
+ if (current_property.Get == null) {
+ report.Error (8146, GetLocation ($4), "`{0}': property and indexer which return by reference must have a get accessor", current_property.GetSignatureForError ());
+ }
+
+ if (current_property.Set != null) {
+ report.Error (8147, GetLocation ($4), "`{0}': property and indexer which return by reference cannot have set accessors", current_property.GetSignatureForError ());
+ }
+ }
current_property = null;
}
: opt_attributes
opt_modifiers
DELEGATE
- member_type type_declaration_name
+ ref_member_type type_declaration_name
OPEN_PARENS
{
valid_param_mod = ParameterModifierType.Ref | ParameterModifierType.Out | ParameterModifierType.Params | ParameterModifierType.DefaultValue;
: {
start_block (Location.Null);
}
- expression // All expressions must handle error or current block won't be restored and breaking ast completely
+ lambda_arrow_expression // All expressions must handle error or current block won't be restored and breaking ast completely
{
Block b = end_block (Location.Null);
b.IsCompilerGenerated = true;
}
;
+lambda_arrow_expression
+ : expression
+ | reference_expression
+ ;
+
expression_or_error
: expression
| error
current_variable = null;
lbag.AddLocation ($$, GetLocation ($1), GetLocation ($7));
}
+ | REF variable_type identifier_inside_body
+ {
+ if (lang_version < LanguageVersion.V_7) {
+ FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+ }
+
+ var lt = (LocatedToken) $3;
+ var li = new LocalVariable (current_block, lt.Value, LocalVariable.Flags.ByRef, lt.Location);
+ current_block.AddLocalName (li);
+ current_variable = new BlockVariable ((FullNamedExpression) $2, li);
+ }
+ opt_local_variable_initializer opt_variable_declarators SEMICOLON
+ {
+ $$ = current_variable;
+ current_variable = null;
+ if ($5 != null) {
+ lbag.AddLocation ($$, PopLocation (), GetLocation ($7));
+ } else {
+ report.Error (8174, GetLocation ($3), "A declaration of a by-reference variable must have an initializer");
+ lbag.AddLocation ($$, GetLocation ($7));
+ }
+ }
;
opt_local_variable_initializer
report.Error (1575, GetLocation ($1), "A stackalloc expression requires [] after type");
$$ = new StackAlloc ((Expression) $2, null, GetLocation ($1));
}
+ | reference_expression
+ ;
+
+reference_expression
+ : REF expression
+ {
+ if (lang_version < LanguageVersion.V_7) {
+ FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+ }
+
+ $$ = new ReferenceExpression ((Expression) $2, GetLocation ($1));
+ }
;
expression_statement
$$ = new Return ((Expression) $2, GetLocation ($1));
lbag.AddStatement ($$, GetLocation ($3));
}
+ | RETURN reference_expression SEMICOLON
+ {
+ $$ = new Return ((Expression) $2, GetLocation ($1));
+ lbag.AddStatement ($$, GetLocation ($3));
+ }
| RETURN expression error
{
Error_SyntaxError (yyToken);
rt = ec.BuiltinTypes.Object;
if (!Delegate.IsTypeCovariant (ec, rt, invoke_method.ReturnType)) {
- Expression ret_expr = new TypeExpression (delegate_method.ReturnType, loc);
- Error_ConversionFailed (ec, delegate_method, ret_expr);
+ Error_ConversionFailed (ec, delegate_method, delegate_method.ReturnType);
}
if (method_group.IsConditionallyExcluded) {
method_group.FlowAnalysis (fc);
}
- void Error_ConversionFailed (ResolveContext ec, MethodSpec method, Expression return_type)
+ void Error_ConversionFailed (ResolveContext ec, MethodSpec method, TypeSpec return_type)
{
var invoke_method = Delegate.GetInvokeMethod (type);
string member_name = method_group.InstanceExpression != null ?
return;
}
+ if (invoke_method.ReturnType.Kind == MemberKind.ByRef) {
+ ec.Report.Error (8189, loc, "By reference return delegate does not match `{0}' return type",
+ Delegate.FullDelegateDesc (invoke_method));
+ return;
+ }
+
ec.Report.Error (407, loc, "A method or delegate `{0} {1}' return type does not match delegate `{2} {3}' return type",
return_type.GetSignatureForError (), member_name,
invoke_method.ReturnType.GetSignatureForError (), Delegate.FullDelegateDesc (invoke_method));
return;
string from_type = type.GetSignatureForError ();
+ if (type.Kind == MemberKind.ByRef)
+ from_type = "ref " + from_type;
string to_type = target.GetSignatureForError ();
+ if (target.Kind == MemberKind.ByRef)
+ to_type = "ref " + to_type;
+
if (from_type == to_type) {
from_type = type.GetSignatureForErrorIncludingAssemblyName ();
to_type = target.GetSignatureForErrorIncludingAssemblyName ();
public Expression ResolveLValue (ResolveContext ec, Expression right_side)
{
int errors = ec.Report.Errors;
- bool out_access = right_side == EmptyExpression.OutAccess;
+ //bool out_access = right_side == EmptyExpression.OutAccess;
Expression e = DoResolveLValue (ec, right_side);
- if (e != null && out_access && !(e is IMemoryLocation)) {
+ //if (e != null && out_access && !(e is IMemoryLocation)) {
// FIXME: There's no problem with correctness, the 'Expr = null' handles that.
// Enabling this 'throw' will "only" result in deleting useless code elsewhere,
//throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
// e.GetType () + " " + e.GetSignatureForError ());
- e = null;
- }
+ // e = null;
+ //}
if (e == null) {
if (errors == ec.Report.Errors) {
if (arg_type == InternalType.VarOutType)
return 0;
+ var ref_arg_type = arg_type as ReferenceContainer;
+ if (ref_arg_type != null) {
+ arg_type = ref_arg_type.Element;
+ }
+
//
// Do full equality check after quick path
//
int arg_count = args == null ? 0 : args.Count;
for (; a_idx < arg_count; a_idx++, ++a_pos) {
- a = args[a_idx];
+ a = args [a_idx];
if (a == null)
continue;
if (p_mod != Parameter.Modifier.PARAMS) {
p_mod = cpd.FixedParameters [a_idx].ModFlags;
- pt = ptypes[a_idx];
+ pt = ptypes [a_idx];
has_unsafe_arg |= pt.IsPointer;
if (p_mod == Parameter.Modifier.PARAMS) {
continue;
}
+ var ref_arg_type = arg_type as ReferenceContainer;
+ if (ref_arg_type != null) {
+ if (ref_arg_type.Element != pt)
+ break;
+
+ return true;
+ }
+
if (!TypeSpecComparer.IsEqual (arg_type, pt))
break;
}
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
if (right_side == EmptyExpression.LValueMemberAccess) {
// Already reported as CS1648/CS1650
- return null;
+ return ErrorExpression.Instance;
}
if (right_side == EmptyExpression.LValueMemberOutAccess) {
rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
if (IsStatic) {
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
Error_NullPropagatingLValue (rc);
if (right_side == EmptyExpression.OutAccess) {
+ if (best_candidate?.MemberType.Kind == MemberKind.ByRef) {
+ if (Arguments?.ContainsEmitWithAwait () == true) {
+ rc.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+ GetSignatureForError ());
+ }
+
+ return this;
+ }
+
// TODO: best_candidate can be null at this point
INamedBlockVariable variable = null;
if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
return;
}
+ bool dereference = IsRef && !(source is ReferenceExpression);
New n_source = source as New;
if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
if (!n_source.Emit (ec, this)) {
if (leave_copy) {
EmitLoad (ec);
- if (IsRef)
+ if (dereference)
ec.EmitLoadFromPtr (type);
}
return;
}
} else {
- if (IsRef)
+ if (dereference)
EmitLoad (ec);
source.Emit (ec);
if (leave_copy) {
ec.Emit (OpCodes.Dup);
- if (IsRef) {
+ if (dereference) {
temp = new LocalTemporary (Type);
temp.Store (ec);
}
}
- if (IsRef)
+ if (dereference)
ec.EmitStoreFromPtr (type);
else
Variable.EmitAssign (ec);
}
public override bool IsRef {
- get { return false; }
+ get { return local_info.IsByRef; }
}
public override string Name {
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
} else if (local_info.IsFixed) {
ec.Report.Error (1764, loc,
- "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
+ "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression",
+ GetSignatureForError ());
+ } else if (local_info.IsByRef) {
+ ec.Report.Error (8175, loc,
+ "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
GetSignatureForError ());
}
protected override Expression DoResolve (ResolveContext rc)
{
ResolveConditionalAccessReceiver (rc);
- return DoResolveInvocation (rc);
+ return DoResolveInvocation (rc, null);
}
public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
return res.Resolve (rc);
}
+ if (right_side != null) {
+ if (eclass != ExprClass.Unresolved)
+ return this;
+
+ var res = DoResolveInvocation (rc, right_side);
+ if (res == null)
+ return null;
+
+ return res;
+ }
+
return base.DoResolveLValue (rc, right_side);
}
- Expression DoResolveInvocation (ResolveContext ec)
+ Expression DoResolveInvocation (ResolveContext ec, Expression rhs)
{
Expression member_expr;
var atn = expr as ATypeNameExpression;
IsSpecialMethodInvocation (ec, method, loc);
eclass = ExprClass.Value;
+
+ if (type.Kind == MemberKind.ByRef) {
+ if (rhs == null && arguments?.ContainsEmitWithAwait () == true) {
+ ec.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+ GetSignatureForError ());
+ }
+
+ if (rhs != EmptyExpression.OutAccess)
+ return ByRefDereference.Create (this).Resolve (ec);
+ }
+
return this;
}
}
}
+ class ReferenceTypeExpr : TypeExpr
+ {
+ FullNamedExpression element;
+
+ public ReferenceTypeExpr (FullNamedExpression element, Location loc)
+ {
+ this.element = element;
+ this.loc = loc;
+ }
+
+ public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
+ {
+ type = element.ResolveAsType (mc);
+ if (type == null)
+ return null;
+
+ eclass = ExprClass.Type;
+ type = ReferenceContainer.MakeType (mc.Module, type);
+
+ return type;
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return "ref " + element.GetSignatureForError ();
+ }
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
+ }
+
class FixedBufferPtr : Expression
{
readonly Expression array;
return Reachability.CreateUnreachable ();
}
}
+
+ class ReferenceExpression : CompositeExpression
+ {
+ public ReferenceExpression (Expression expr, Location loc)
+ : base (expr)
+ {
+ this.loc = loc;
+ }
+
+ static bool CanBeByRef (Expression expr)
+ {
+ if (expr is IAssignMethod)
+ return true;
+
+ var invocation = expr as Invocation;
+ if (invocation?.Type.Kind == MemberKind.ByRef)
+ return true;
+
+ return false;
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext rc)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess);
+ if (res == null || !CanBeByRef (res)) {
+ if (res?.Type != InternalType.ErrorType)
+ rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference");
+ return ErrorExpression.Instance;
+ }
+
+ type = res.Type;
+ var type_container = type as ReferenceContainer;
+ if (type_container != null)
+ type = type_container.Element;
+
+ expr = res;
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ var ml = expr as IMemoryLocation;
+ if (ml != null)
+ ml.AddressOf (ec, AddressOp.LoadStore);
+ else
+ expr.Emit (ec);
+ }
+
+ public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
+ {
+ rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ());
+ }
+ }
+
+ class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod
+ {
+ bool prepared;
+ LocalTemporary temporary;
+
+ private ByRefDereference (Expression expr)
+ : base (expr)
+ {
+ }
+
+ public static Expression Create (Expression expr)
+ {
+ var rc = expr.Type as ReferenceContainer;
+ if (rc == null)
+ return expr;
+
+ return new ByRefDereference (expr) {
+ type = rc.Element
+ };
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ expr.Emit (ec);
+ }
+
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ Emit (ec);
+ if (leave_copy) {
+ ec.Emit (OpCodes.Dup);
+ temporary = new LocalTemporary (type);
+ temporary.Store (ec);
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
+ {
+ prepared = isCompound;
+
+ expr.Emit (ec);
+
+ if (isCompound)
+ ec.Emit (OpCodes.Dup);
+
+ source.Emit (ec);
+ if (leave_copy) {
+ throw new NotImplementedException ("leave_copy");
+ }
+
+ ec.EmitStoreFromPtr (type);
+
+ if (temporary != null) {
+ temporary.Emit (ec);
+ temporary.Release (ec);
+ }
+ }
+
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ eclass = ExprClass.Variable;
+ return this;
+ }
+
+ public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+ {
+ return DoResolve (rc);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (!prepared)
+ base.Emit(ec);
+
+ ec.EmitLoadFromPtr (type);
+ }
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
+ }
}
if (ec is PointerContainer)
return PointerContainer.MakeType (context.Module, et);
+ if (ec is ReferenceContainer)
+ return ReferenceContainer.MakeType (context.Module, et);
+
throw new NotImplementedException ();
}
return;
if (!CheckType (ret, parent, out iterator_type, out is_enumerable)) {
- parent.Compiler.Report.Error (1624, method.Location,
- "The body of `{0}' cannot be an iterator block " +
- "because `{1}' is not an iterator interface type",
- method.GetSignatureForError (),
- ret.GetSignatureForError ());
+ if (ret.Kind == MemberKind.ByRef) {
+ parent.Compiler.Report.Error (8154, method.Location,
+ "The body of `{0}' cannot be an iterator block because the method returns by reference",
+ method.GetSignatureForError ());
+ } else {
+ parent.Compiler.Report.Error (1624, method.Location,
+ "The body of `{0}' cannot be an iterator block because `{1}' is not an iterator interface type",
+ method.GetSignatureForError (), ret.GetSignatureForError ());
+ }
return;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
+ if (Expr is ReferenceExpression) {
+ ec.Report.Error (8155, Expr.Location, "Lambda expressions that return by reference cannot be converted to expression trees");
+ return null;
+ }
+
return Expr.CreateExpressionTree (ec);
}
if (Expr == null)
return false;
+ if (Expr is ReferenceExpression) {
+ // CSC: should be different error code
+ ec.Report.Error (8149, loc, "By-reference returns can only be used in lambda expressions that return by reference");
+ return false;
+ }
+
statement = Expr as ExpressionStatement;
if (statement == null) {
var reduced = Expr as IReducedExpressionStatement;
Enum = 1 << 14,
Interface = 1 << 15,
TypeParameter = 1 << 16,
+ ByRef = 1 << 17,
ArrayType = 1 << 19,
PointerType = 1 << 20,
Report.Error (737, container.Location,
"`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is not public",
container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
+ } else if (mi.ReturnType.Kind == MemberKind.ByRef) {
+ Report.Error (8152, container.Location,
+ "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not return by reference",
+ container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError (),
+ candidate.ReturnType.GetSignatureForError ());
} else {
Report.Error (738, container.Location,
"`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not match interface member return type `{4}'",
return false;
}
+ if (MemberType.Kind == MemberKind.ByRef) {
+ Report.Error (8145, Location, "Auto-implemented properties cannot return by reference");
+ return false;
+ }
+
if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");
if (expr == null)
return false;
+ if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
+ ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
+ return false;
+ }
+
if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
- expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+ if (block_return_type.Kind == MemberKind.ByRef) {
+ var ref_expr = Expr as ReferenceExpression;
+ if (ref_expr == null) {
+ ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
+ return false;
+ }
- if (expr == null) {
- if (am != null && block_return_type == ec.ReturnType) {
- ec.Report.Error (1662, loc,
- "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
- am.ContainerType, am.GetSignatureForError ());
+ var byref_return = (ReferenceContainer)block_return_type;
+
+ if (expr.Type != byref_return.Element) {
+ ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
+ byref_return.GetSignatureForError ());
+ return false;
+ }
+ } else {
+
+ expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+
+ if (expr == null) {
+ if (am != null && block_return_type == ec.ReturnType) {
+ ec.Report.Error (1662, loc,
+ "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+ am.ContainerType, am.GetSignatureForError ());
+ }
+ return false;
}
- return false;
}
}
}
if (type == null) {
- type = type_expr.ResolveAsType (bc);
+ type = ResolveTypeExpression (bc);
if (type == null)
return false;
}
if (initializer != null) {
+ if (li.IsByRef) {
+ if (!(initializer is ReferenceExpression)) {
+ bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
+ return false;
+ }
+
+ if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+ bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
+ } else if (bc.CurrentIterator != null) {
+ bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
+ }
+
+ } else {
+ if (initializer is ReferenceExpression) {
+ bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
+ return false;
+ }
+ }
+
initializer = ResolveInitializer (bc, li, initializer);
// li.Variable.DefinitelyAssigned
}
return a.ResolveStatement (bc);
}
+ protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+ {
+ return type_expr.ResolveAsType (bc);
+ }
+
protected override void DoEmit (EmitContext ec)
{
li.CreateBuilder (ec);
UsingVariable = 1 << 7,
IsLocked = 1 << 8,
SymbolFileHidden = 1 << 9,
+ ByRef = 1 << 10,
ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
}
}
}
+ public bool IsByRef => (flags & Flags.ByRef) != 0;
+
public bool IsCompilerGenerated {
get {
return (flags & Flags.CompilerGenerated) != 0;
throw new InternalErrorException ("Already created variable `{0}'", name);
}
- //
- // All fixed variabled are pinned, a slot has to be alocated
- //
- builder = ec.DeclareLocal (Type, IsFixed);
+ if (IsByRef) {
+ builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
+ } else {
+ //
+ // All fixed variabled are pinned, a slot has to be alocated
+ //
+ builder = ec.DeclareLocal(Type, IsFixed);
+ }
+
if ((flags & Flags.SymbolFileHidden) == 0)
ec.DefineLocalVariable (name, builder);
}
if ((flags & Flags.CompilerGenerated) != 0)
CreateBuilder (ec);
- ec.Emit (OpCodes.Ldloca, builder);
+ if (IsByRef)
+ ec.Emit (OpCodes.Ldloc, builder);
+ else
+ ec.Emit (OpCodes.Ldloca, builder);
}
public static string GetCompilerGeneratedName (Block block)
}
}
+ [System.Diagnostics.DebuggerDisplay("{DisplayDebugInfo()}")]
class ReferenceContainer : ElementTypeSpec
{
ReferenceContainer (TypeSpec element)
- : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
+ : base (MemberKind.ByRef, element, null)
{
}
}
}
+ string DisplayDebugInfo()
+ {
+ return "ref " + GetSignatureForError();
+ }
+
public override MetaType GetMetaInfo ()
{
if (info == null) {
return info;
}
+ public override string GetSignatureForError ()
+ {
+ return Element.GetSignatureForError ();
+ }
+
public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
{
+ if (element.Kind == MemberKind.ByRef)
+ throw new ArgumentException ();
+
ReferenceContainer pc;
if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
pc = new ReferenceContainer (element);
--- /dev/null
+// Compiler options: -unsafe
+
+public unsafe class X
+{
+ int field;
+ int* ufield;
+
+ public static void Main ()
+ {
+ int i = 5;
+ ref int j = ref i;
+
+ var x = new X ();
+ ref var v = ref x.TestMethod ();
+ }
+
+ ref int TestMethod ()
+ {
+ return ref field;
+ }
+
+ ref int TestProperty {
+ get {
+ return ref field;
+ }
+ }
+
+ ref int this [long arg] {
+ get {
+ return ref field;
+ }
+ }
+
+ unsafe ref int* Foo ()
+ {
+ return ref ufield;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+class X
+{
+ int field;
+
+ static void Main ()
+ {
+ var x = new X ();
+ x.Run ();
+ }
+
+ void Run ()
+ {
+ Test (ref this[0]);
+ Test (ref Prop);
+ }
+
+ static int Test (ref int y)
+ {
+ return y;
+ }
+
+ ref int this [int y] {
+ get {
+ return ref field;
+ }
+ }
+
+ ref int Prop {
+ get {
+ return ref field;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+class X
+{
+ int x;
+
+ static void Main ()
+ {
+ var x = new X ();
+ Foo (ref x.Wrap (1));
+ Foo (ref x.Prop);
+ Foo (ref x[""]);
+ }
+
+ ref int Wrap (int arg)
+ {
+ return ref x;
+ }
+
+ ref int Prop {
+ get {
+ return ref x;
+ }
+ }
+
+ ref int this [string arg] {
+ get {
+ return ref x;
+ }
+ }
+
+ static void Foo (ref int arg)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+class X
+{
+ int field;
+
+ public static int Main ()
+ {
+ var x = new X ();
+
+ x.field = 5;
+ if (!x.Test1 ())
+ return 1;
+
+ x.Test2 ();
+
+ if (x.Test3 ()++ != 6)
+ return 2;
+
+ if (x.field != 7)
+ return 3;
+
+ return 0;
+ }
+
+ bool Test1 ()
+ {
+ ref var x = ref field;
+ int v = x;
+ ++x;
+
+ return x == 6;
+ }
+
+ void Test2 ()
+ {
+ ref int x = ref field;
+ x.ToString ();
+ }
+
+ ref int Test3 ()
+ {
+ ref int l = ref field;
+ ref int v = ref l;
+ return ref l;
+ }
+}
\ No newline at end of file
--- /dev/null
+class X
+{
+ static int field;
+
+ public static int Main ()
+ {
+ Test () = 3;
+
+ if (field != (byte) 3)
+ return 1;
+
+ G<string>.Test (ref field) = 6;
+ if (field != 6)
+ return 2;
+
+ --Test ();
+ if (field != 5)
+ return 3;
+
+ Test (ref Test (), ref Test ());
+
+ return 0;
+ }
+
+ static ref int Test ()
+ {
+ return ref field;
+ }
+
+ static void Test<T> (ref T a, ref int b)
+ {
+ }
+
+ static void Test2<T> (ref T arg)
+ {
+ Test (ref arg, ref Test ());
+ }
+}
+
+class G<U>
+{
+ public static ref T Test<T> (ref T arg)
+ {
+ return ref arg;
+ }
+}
\ No newline at end of file
</method>
</type>
</test>
+ <test name="test-ref-01.cs">
+ <type name="X">
+ <method name="Void Main()" attrs="150">
+ <size>20</size>
+ </method>
+ <method name="Int32& TestMethod()" attrs="129">
+ <size>15</size>
+ </method>
+ <method name="Int32& get_TestProperty()" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Int32& get_Item(Int64)" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Int32*& Foo()" attrs="129">
+ <size>15</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-ref-02.cs">
+ <type name="X">
+ <method name="Void Main()" attrs="145">
+ <size>14</size>
+ </method>
+ <method name="Void Run()" attrs="129">
+ <size>27</size>
+ </method>
+ <method name="Int32 Test(Int32 ByRef)" attrs="145">
+ <size>11</size>
+ </method>
+ <method name="Int32& get_Item(Int32)" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Int32& get_Prop()" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-ref-03.cs">
+ <type name="X">
+ <method name="Void Main()" attrs="145">
+ <size>47</size>
+ </method>
+ <method name="Int32& Wrap(Int32)" attrs="129">
+ <size>15</size>
+ </method>
+ <method name="Int32& get_Prop()" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Int32& get_Item(System.String)" attrs="2177">
+ <size>15</size>
+ </method>
+ <method name="Void Foo(Int32 ByRef)" attrs="145">
+ <size>2</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-ref-04.cs">
+ <type name="X">
+ <method name="Int32 Main()" attrs="150">
+ <size>93</size>
+ </method>
+ <method name="Boolean Test1()" attrs="129">
+ <size>30</size>
+ </method>
+ <method name="Void Test2()" attrs="129">
+ <size>22</size>
+ </method>
+ <method name="Int32& Test3()" attrs="129">
+ <size>19</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
+ <test name="test-ref-05.cs">
+ <type name="X">
+ <method name="Int32 Main()" attrs="150">
+ <size>108</size>
+ </method>
+ <method name="Int32& Test()" attrs="145">
+ <size>14</size>
+ </method>
+ <method name="Void Test[T](T ByRef, Int32 ByRef)" attrs="145">
+ <size>2</size>
+ </method>
+ <method name="Void Test2[T](T ByRef)" attrs="145">
+ <size>13</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="G`1[U]">
+ <method name="T& Test[T](T ByRef)" attrs="150">
+ <size>10</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-static-using-01.cs">
<type name="A.B.X">
<method name="Int32 Test()" attrs="150">