Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
b26fc0dc
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b26fc0dc
编写于
8月 14, 2017
作者:
V
vsadov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Ternary ref branches must have matching ref-escapes
上级
3c7e7ac9
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
144 addition
and
11 deletion
+144
-11
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
+6
-8
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
+27
-1
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+9
-0
src/Compilers/CSharp/Portable/CSharpResources.resx
src/Compilers/CSharp/Portable/CSharpResources.resx
+4
-1
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+2
-1
src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
...pilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
+96
-0
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
浏览文件 @
b26fc0dc
...
...
@@ -1518,15 +1518,14 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expr
;
// byref conditional defers to
its operands
// byref conditional defers to
one operand. Since are here without errors, both operands must match.
if
(
conditional
.
IsByRef
&&
(
CheckRefEscape
(
conditional
.
Consequence
.
Syntax
,
conditional
.
Consequence
,
escapeFrom
,
escapeTo
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
)
&&
CheckRefEscape
(
conditional
.
Alternative
.
Syntax
,
conditional
.
Alternative
,
escapeFrom
,
escapeTo
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
)))
CheckRefEscape
(
conditional
.
Consequence
.
Syntax
,
conditional
.
Consequence
,
escapeFrom
,
escapeTo
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
))
{
return
true
;
}
// rep
ro
t standard lvalue error
// rep
or
t standard lvalue error
break
;
case
BoundKind
.
FieldAccess
:
...
...
@@ -1691,14 +1690,13 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expr
;
// byref conditional defers to
its operands
// byref conditional defers to
one operand. Since are here without errors, both operands must match.
if
(
conditional
.
IsByRef
)
{
return
Math
.
Max
(
GetRefEscape
(
conditional
.
Consequence
,
scopeOfTheContainingExpression
),
GetRefEscape
(
conditional
.
Alternative
,
scopeOfTheContainingExpression
));
return
GetRefEscape
(
conditional
.
Consequence
,
scopeOfTheContainingExpression
);
}
//
report standard lvalue error
//
otherwise it is an RValue
break
;
case
BoundKind
.
FieldAccess
:
...
...
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
浏览文件 @
b26fc0dc
...
...
@@ -3524,7 +3524,7 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
{
diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalNeedsTwoRefs
,
whenTrue
.
GetFirstToken
().
GetLocation
());
}
}
}
BoundExpression
condition
=
BindBooleanExpression
(
node
.
Condition
,
diagnostics
);
...
...
@@ -3636,6 +3636,32 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
}
}
if
(!
hasErrors
&&
isRef
)
{
var
currentScope
=
this
.
LocalScopeDepth
;
// ref-escape must agree on both branches.
var
whenTrueEscape
=
GetRefEscape
(
trueExpr
,
currentScope
);
var
whenFalseEscape
=
GetRefEscape
(
falseExpr
,
currentScope
);
if
(
whenTrueEscape
!=
whenFalseEscape
)
{
// ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix.
if
(
whenTrueEscape
<
whenFalseEscape
)
{
CheckRefEscape
(
falseExpr
.
Syntax
,
falseExpr
,
currentScope
,
whenTrueEscape
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
);
}
else
{
CheckRefEscape
(
trueExpr
.
Syntax
,
trueExpr
,
currentScope
,
whenFalseEscape
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
);
}
diagnostics
.
Add
(
ErrorCode
.
ERR_MismatchedRefEscapeInTernary
,
node
.
Location
);
hasErrors
=
true
;
}
}
ConstantValue
constantValue
=
null
;
if
(!
hasErrors
)
...
...
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
浏览文件 @
b26fc0dc
...
...
@@ -6307,6 +6307,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes..
/// </summary>
internal static string ERR_MismatchedRefEscapeInTernary {
get {
return ResourceManager.GetString("ERR_MismatchedRefEscapeInTernary", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Argument missing.
/// </summary>
...
...
src/Compilers/CSharp/Portable/CSharpResources.resx
浏览文件 @
b26fc0dc
...
...
@@ -4867,7 +4867,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
</data>
<data
name=
"ERR_CallArgMixing"
xml:space=
"preserve"
>
<value>
This combination of arguments to '{0}' is disallowed because it may expose variables referenced by parameter '{1}' outside of their declaration scope
</value>
</data>
</data>
<data
name=
"ERR_MismatchedRefEscapeInTernary"
xml:space=
"preserve"
>
<value>
Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
</value>
</data>
<data
name=
"ERR_InitializeByValueVariableWithReference"
xml:space=
"preserve"
>
<value>
Cannot initialize a by-value variable with a reference
</value>
</data>
...
...
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
浏览文件 @
b26fc0dc
...
...
@@ -1531,6 +1531,7 @@ internal enum ErrorCode
ERR_EscapeCall2
=
8522
,
ERR_EscapeOther
=
8523
,
ERR_CallArgMixing
=
8524
,
ERR_EscapeLocal
=
8525
,
ERR_MismatchedRefEscapeInTernary
=
8525
,
ERR_EscapeLocal
=
8526
,
}
}
src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs
浏览文件 @
b26fc0dc
...
...
@@ -941,5 +941,101 @@ static S1 MayWrap(in int arg)
Diagnostic
(
ErrorCode
.
ERR_CallArgMixing
,
"MayAssign(ref rOuter)"
).
WithArguments
(
"Program.MayAssign(ref Program.S1, in int)"
,
"arg2"
).
WithLocation
(
16
,
13
)
);
}
[
Fact
()]
public
void
MismatchedRefTernaryEscape
()
{
var
text
=
@"
class Program
{
static void Main()
{
}
public static int field = 1;
void Test1()
{
var local = 42;
ref var ternary1 = ref true ? ref field : ref local;
ref var lr = ref local;
ref var fr = ref field;
ref var ternary2 = ref true ? ref field : ref local;
}
}
"
;
CreateStandardCompilation
(
text
).
VerifyDiagnostics
(
// (13,55): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// ref var ternary1 = ref true ? ref field : ref local;
Diagnostic
(
ErrorCode
.
ERR_RefReturnLocal
,
"local"
).
WithArguments
(
"local"
).
WithLocation
(
13
,
55
),
// (13,32): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var ternary1 = ref true ? ref field : ref local;
Diagnostic
(
ErrorCode
.
ERR_MismatchedRefEscapeInTernary
,
"true ? ref field : ref local"
).
WithLocation
(
13
,
32
),
// (18,55): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// ref var ternary2 = ref true ? ref field : ref local;
Diagnostic
(
ErrorCode
.
ERR_RefReturnLocal
,
"local"
).
WithArguments
(
"local"
).
WithLocation
(
18
,
55
),
// (18,32): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var ternary2 = ref true ? ref field : ref local;
Diagnostic
(
ErrorCode
.
ERR_MismatchedRefEscapeInTernary
,
"true ? ref field : ref local"
).
WithLocation
(
18
,
32
));
}
[
Fact
()]
public
void
MismatchedRefTernaryEscapeBlock
()
{
var
text
=
@"
class Program
{
static void Main()
{
}
public static int field = 1;
void Test1()
{
var outer = 42;
var sOuter = MayWrap(ref outer);
{
var inner = 42;
var sInner = MayWrap(ref inner);
ref var ternary1 = ref true ? ref sOuter[1] : ref sInner[1];
ref var ir = ref sInner[1];
ref var or = ref sOuter[1];
ref var ternary2 = ref true ? ref ir : ref or;
}
}
static S1 MayWrap(ref int arg)
{
return default;
}
ref struct S1
{
public ref int this[int i] => throw null;
}
}
"
;
CreateStandardCompilation
(
text
).
VerifyDiagnostics
(
// (19,63): error CS8520: Cannot use local 'sInner' in this context because it may expose referenced variables outside of their declaration scope
// ref var ternary1 = ref true ? ref sOuter[1] : ref sInner[1];
Diagnostic
(
ErrorCode
.
ERR_EscapeLocal
,
"sInner"
).
WithArguments
(
"sInner"
).
WithLocation
(
19
,
63
),
// (19,36): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var ternary1 = ref true ? ref sOuter[1] : ref sInner[1];
Diagnostic
(
ErrorCode
.
ERR_MismatchedRefEscapeInTernary
,
"true ? ref sOuter[1] : ref sInner[1]"
).
WithLocation
(
19
,
36
),
// (24,47): error CS8520: Cannot use local 'ir' in this context because it may expose referenced variables outside of their declaration scope
// ref var ternary2 = ref true ? ref ir : ref or;
Diagnostic
(
ErrorCode
.
ERR_EscapeLocal
,
"ir"
).
WithArguments
(
"ir"
).
WithLocation
(
24
,
47
),
// (24,36): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var ternary2 = ref true ? ref ir : ref or;
Diagnostic
(
ErrorCode
.
ERR_MismatchedRefEscapeInTernary
,
"true ? ref ir : ref or"
).
WithLocation
(
24
,
36
)
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录