提交 c39494af 编写于 作者: V vsadov

Regular assignments do escape analysis

上级 7abde2f9
......@@ -1399,9 +1399,9 @@ private BoundExpression SynthesizeMethodGroupReceiver(CSharpSyntaxNode syntax, A
}
}
private bool IsBadLocalOrParameterCapture(Symbol symbol, RefKind refKind)
private bool IsBadLocalOrParameterCapture(Symbol symbol, TypeSymbol type, RefKind refKind)
{
if (refKind != RefKind.None)
if (refKind != RefKind.None || type.IsByRefLikeType )
{
var containingMethod = this.ContainingMemberOrLambda as MethodSymbol;
if ((object)containingMethod != null && (object)symbol.ContainingSymbol != (object)containingMethod)
......@@ -1514,8 +1514,10 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
else
{
type = localSymbol.Type;
if (IsBadLocalOrParameterCapture(localSymbol, localSymbol.RefKind))
if (IsBadLocalOrParameterCapture(localSymbol, type, localSymbol.RefKind))
{
isError = true;
//PROTOTYPE(span): need a better error message for invalid span captures (should not say ref)
Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseLocal, node, localSymbol);
}
}
......@@ -1528,8 +1530,10 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
case SymbolKind.Parameter:
{
var parameter = (ParameterSymbol)symbol;
if (IsBadLocalOrParameterCapture(parameter, parameter.RefKind))
if (IsBadLocalOrParameterCapture(parameter, parameter.Type, parameter.RefKind))
{
isError = true;
//PROTOTYPE(span): need a better error message for invalid in/span captures (should not say ref/out)
Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUse, node, parameter.Name);
}
return new BoundParameter(node, parameter, hasErrors: isError);
......
......@@ -1229,6 +1229,12 @@ private BoundAssignmentOperator BindAssignment(SyntaxNode node, BoundExpression
{
op2 = conversion;
}
if (op1.Type.IsByRefLikeType)
{
var leftEscape = GetValEscape(op1, this.LocalScopeDepth);
op2 = ValidateEscape(op2, leftEscape, isByRef: false, diagnostics: diagnostics);
}
}
TypeSymbol type;
......@@ -2321,11 +2327,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, DiagnosticBag di
{
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
arg = BindValue(expressionSyntax, diagnostics, requiredValueKind);
if (refKind != RefKind.None)
{
arg = EnsureRefEscape(arg, Binder.ExternalScope, diagnostics);
}
arg = ValidateEscape(arg, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
}
else
{
......@@ -2801,11 +2803,7 @@ private static bool IsValidExpressionBody(SyntaxNode expressionSyntax, BoundExpr
ExpressionSyntax expressionSyntax = expressionBody.Expression.CheckAndUnwrapRefExpression(diagnostics, out refKind);
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, requiredValueKind);
if (refKind != RefKind.None)
{
expression = EnsureRefEscape(expression, Binder.ExternalScope, diagnostics);
}
expression = ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(expressionBody, bodyBinder.GetDeclaredLocalsForScope(expressionBody), refKind, expression, expressionSyntax, diagnostics);
}
......@@ -2822,11 +2820,7 @@ public BoundBlock BindLambdaExpressionAsBlock(ExpressionSyntax body, DiagnosticB
var expressionSyntax = body.CheckAndUnwrapRefExpression(diagnostics, out refKind);
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, requiredValueKind);
if (refKind != RefKind.None)
{
expression = EnsureRefEscape(expression, Binder.ExternalScope, diagnostics);
}
expression = ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(body, bodyBinder.GetDeclaredLocalsForScope(body), refKind, expression, expressionSyntax, diagnostics);
}
......
......@@ -39,7 +39,7 @@ internal LocalScopeBinder(Binder next, BinderFlags flags)
var parentScope = next;
while(parentScope != null)
{
if (parentScope is InMethodBinder)
if (parentScope is InMethodBinder || parentScope is WithLambdaParametersBinder)
{
_localScopeDepth = Binder.TopLevelScope;
break;
......
......@@ -169,5 +169,7 @@ internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsF
{
throw ExceptionUtilities.Unreachable;
}
internal override uint LocalScopeDepth => Binder.TopLevelScope;
}
}
......@@ -46,9 +46,12 @@ static S1 Test2(ref int arg)
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (21,30): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// (21,40): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "Test2(ref local)").WithLocation(21, 30),
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(21, 40),
// (21,30): error CS8164: Cannot return by reference a result of 'Program.Test2(ref int)' because the argument passed to parameter 'arg' cannot be returned by reference
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_RefReturnCall, "Test2(ref local)").WithArguments("Program.Test2(ref int)", "arg").WithLocation(21, 30),
// (21,24): error CS8164: Cannot return by reference a result of 'Program.Test1(Program.S1)' because the argument passed to parameter 'arg' cannot be returned by reference
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_RefReturnCall, "Test1(Test2(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
......@@ -93,5 +96,96 @@ static S1 Test2(ref int arg)
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "sp").WithLocation(22, 30)
);
}
[Fact()]
public void SimpleRefLikeReturnEscapeInParam()
{
var text = @"
class Program
{
static void Main()
{
}
static ref int Test1(S1 arg)
{
return ref (new int[1])[0];
}
static S1 Test2(in int arg)
{
return default;
}
static ref int Test3()
{
int local = 42;
var sp = Test2(local);
// not an error
sp = Test2(local);
// not an error
sp = sp;
// error here
return ref Test1(sp);
}
ref struct S1
{
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (30,30): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref Test1(sp);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "sp").WithLocation(30, 30),
// (27,13): warning CS1717: Assignment made to same variable; did you mean to assign something else?
// sp = sp;
Diagnostic(ErrorCode.WRN_AssignmentToSelf, "sp = sp").WithLocation(27, 13)
);
}
[Fact()]
public void SimpleRefLikeReturnEscapeInParamOptional()
{
var text = @"
class Program
{
static void Main()
{
}
static ref int Test1(S1 arg)
{
return ref (new int[1])[0];
}
static S1 Test2(in int arg = 123)
{
return default;
}
static ref int Test3()
{
// error here
return ref Test1(Test2());
}
ref struct S1
{
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (21,30): error CS8164: Cannot return by reference a result of 'Program.Test2(in int)' because the argument passed to parameter 'arg' cannot be returned by reference
// return ref Test1(Test2());
Diagnostic(ErrorCode.ERR_RefReturnCall, "Test2()").WithArguments("Program.Test2(in int)", "arg").WithLocation(21, 30),
// (21,24): error CS8164: Cannot return by reference a result of 'Program.Test1(Program.S1)' because the argument passed to parameter 'arg' cannot be returned by reference
// return ref Test1(Test2());
Diagnostic(ErrorCode.ERR_RefReturnCall, "Test1(Test2())").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
);
}
}
}
......@@ -903,9 +903,6 @@ public static void Main()
// (16,54): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression
// ref char Moo1(ref char a, ref char b) => ref r;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(16, 54),
// (16,54): error CS8151: The return expression must be of type 'char' because this method returns by reference
// ref char Moo1(ref char a, ref char b) => ref r;
Diagnostic(ErrorCode.ERR_RefReturnMustHaveIdentityConversion, "r").WithArguments("char").WithLocation(16, 54),
// (17,46): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression
// char Moo3(ref char a, ref char b) => r;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(17, 46),
......@@ -926,7 +923,8 @@ public static void Main()
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Moo1").WithArguments("Moo1").WithLocation(16, 18),
// (17,14): warning CS8321: The local function 'Moo3' is declared but never used
// char Moo3(ref char a, ref char b) => r;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Moo3").WithArguments("Moo3").WithLocation(17, 14));
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Moo3").WithArguments("Moo3").WithLocation(17, 14)
);
}
[Fact, WorkItem(13062, "https://github.com/dotnet/roslyn/issues/13062")]
......
......@@ -92,11 +92,11 @@ static void Main()
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): make this bind-time diagnostic?
comp.VerifyEmitDiagnostics(
// (17,29): error CS4013: Instance of type 'Span<int>' cannot be used inside an anonymous function, query expression, iterator block or async method
//PROTOTYPE(span): need a better error message for invalid span captures (should not say ref)
comp.VerifyDiagnostics(
// (17,29): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression
// Func<int> f = () => x[1];
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "x").WithArguments("System.Span<int>").WithLocation(17, 29)
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(17, 29)
);
}
......@@ -123,14 +123,17 @@ class C1<T> where T: Span<int>
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): make this bind-time diagnostic?
//PROTOTYPE(span): need a better error message for invalid span captures (should not say ref)
comp.VerifyDiagnostics(
// (13,26): error CS0701: 'Span<int>' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
// class C1<T> where T: Span<int>
Diagnostic(ErrorCode.ERR_BadBoundType, "Span<int>").WithArguments("System.Span<int>").WithLocation(13, 26),
// (10,14): error CS0306: The type 'Span<int>' may not be used as a type argument
// Func<Span<int>> d = ()=>x;
Diagnostic(ErrorCode.ERR_BadTypeArgument, "Span<int>").WithArguments("System.Span<int>").WithLocation(10, 14)
Diagnostic(ErrorCode.ERR_BadTypeArgument, "Span<int>").WithArguments("System.Span<int>").WithLocation(10, 14),
// (10,33): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression
// Func<Span<int>> d = ()=>x;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(10, 33)
);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册