提交 56e5c826 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #21334 from VSadov/safety001

Implementing escape tracking/validation for refs and ref-like values
......@@ -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);
......@@ -3337,17 +3341,32 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
ReportDiagnosticsIfObsolete(diagnostics, resultMember, nonNullSyntax, hasBaseReceiver: isBaseConstructorInitializer);
var arguments = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
hasErrors |= !CheckInvocationArgMixing(
nonNullSyntax,
resultMember,
receiver,
resultMember.Parameters,
arguments,
refKinds,
argsToParamsOpt,
this.LocalScopeDepth,
diagnostics);
return new BoundCall(
nonNullSyntax,
receiver,
resultMember,
analyzedArguments.Arguments.ToImmutable(),
arguments,
analyzedArguments.GetNames(),
analyzedArguments.RefKinds.ToImmutableOrNull(),
refKinds,
isDelegateCall: false,
expanded: memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm,
invokedAsExtensionMethod: false,
argsToParamsOpt: memberResolutionResult.Result.ArgsToParamsOpt,
argsToParamsOpt: argsToParamsOpt,
resultKind: LookupResultKind.Viable,
binderOpt: this,
type: constructorReturnType,
......@@ -4432,15 +4451,29 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
FoldParameterlessValueTypeConstructor(type) :
null;
var arguments = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var argToParams = memberResolutionResult.Result.ArgsToParamsOpt;
hasError |= !CheckInvocationArgMixing(
node,
method,
null,
method.Parameters,
arguments,
refKinds,
argToParams,
this.LocalScopeDepth,
diagnostics);
result = new BoundObjectCreationExpression(
node,
method,
candidateConstructors,
analyzedArguments.Arguments.ToImmutable(),
arguments,
analyzedArguments.GetNames(),
analyzedArguments.RefKinds.ToImmutableOrNull(),
refKinds,
memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm,
memberResolutionResult.Result.ArgsToParamsOpt,
argToParams,
constantValueOpt,
boundInitializerOpt,
this,
......@@ -6743,11 +6776,23 @@ private BoundExpression BindIndexedPropertyAccess(SyntaxNode syntax, BoundExpres
gotError = IsRefOrOutThisParameterCaptured(syntax, diagnostics);
}
var arguments = analyzedArguments.Arguments.ToImmutable();
gotError |= !CheckInvocationArgMixing(
syntax,
property,
receiver,
property.Parameters,
arguments,
argumentRefKinds,
argsToParams,
this.LocalScopeDepth,
diagnostics);
propertyAccess = new BoundIndexerAccess(
syntax,
receiver,
property,
analyzedArguments.Arguments.ToImmutable(),
arguments,
argumentNames,
argumentRefKinds,
isExpanded,
......
......@@ -1013,6 +1013,17 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
Debug.Assert(args.IsDefaultOrEmpty || (object)receiver != (object)args[0]);
gotError |= !CheckInvocationArgMixing(
node,
method,
receiver,
method.Parameters,
args,
argRefKinds,
argsToParams,
this.LocalScopeDepth,
diagnostics);
if ((object)delegateTypeOpt != null)
{
return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: true,
......
......@@ -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,31 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
}
}
if (!hasErrors && isRef)
{
var currentScope = this.LocalScopeDepth;
// ref-escape must agree on both branches.
uint whenTrueEscape = GetRefEscape(trueExpr, currentScope);
uint 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)
......
......@@ -947,14 +947,16 @@ private TypeSymbol BindVariableType(CSharpSyntaxNode declarationNode, Diagnostic
localSymbol.SetType(declTypeOpt);
if (localSymbol.RefKind != RefKind.None && initializerOpt != null)
if (initializerOpt != null)
{
var ignoredDiagnostics = DiagnosticBag.GetInstance();
if (this.CheckValueKind(initializerOpt.Syntax, initializerOpt, BindValueKind.ReturnableReference, checkingReceiver: false, diagnostics: ignoredDiagnostics))
var currentScope = LocalScopeDepth;
localSymbol.SetValEscape(GetValEscape(initializerOpt, currentScope));
if (localSymbol.RefKind != RefKind.None)
{
localSymbol.SetReturnable();
localSymbol.SetRefEscape(GetRefEscape(initializerOpt, currentScope));
}
ignoredDiagnostics.Free();
}
ImmutableArray<BoundExpression> arguments = BindDeclaratorArguments(declarator, localDiagnostics);
......@@ -1227,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;
......@@ -1407,6 +1415,13 @@ protected virtual LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken)
return Next.LookupLocalFunction(nameToken);
}
/// <summary>
/// Returns a value that tells how many local scopes are visible, including the current.
/// I.E. outside of any method will be 0
/// immediately inside a method - 1
/// </summary>
internal virtual uint LocalScopeDepth => Next.LocalScopeDepth;
internal BoundBlock BindEmbeddedBlock(BlockSyntax node, DiagnosticBag diagnostics)
{
return BindBlock(node, diagnostics);
......@@ -2312,6 +2327,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, DiagnosticBag di
{
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
arg = BindValue(expressionSyntax, diagnostics, requiredValueKind);
arg = ValidateEscape(arg, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
}
else
{
......@@ -2787,6 +2803,8 @@ 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);
expression = ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(expressionBody, bodyBinder.GetDeclaredLocalsForScope(expressionBody), refKind, expression, expressionSyntax, diagnostics);
}
......@@ -2802,6 +2820,8 @@ public BoundBlock BindLambdaExpressionAsBlock(ExpressionSyntax body, DiagnosticB
var expressionSyntax = body.CheckAndUnwrapRefExpression(diagnostics, out refKind);
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, requiredValueKind);
expression = ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(body, bodyBinder.GetDeclaredLocalsForScope(body), refKind, expression, expressionSyntax, diagnostics);
}
......@@ -2813,7 +2833,7 @@ private BindValueKind GetRequiredReturnValueKind(RefKind refKind)
GetCurrentReturnType(out var sigRefKind);
requiredValueKind = sigRefKind == RefKind.Ref ?
BindValueKind.RefReturn :
BindValueKind.RefReadonlyReturn;
BindValueKind.ReadonlyRef;
}
return requiredValueKind;
......
......@@ -42,6 +42,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return null;
}
internal override uint LocalScopeDepth => Binder.ExternalScope;
internal override bool IsAccessibleHelper(Symbol symbol, TypeSymbol accessThroughType, out bool failedThroughTypeCheck, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved)
{
failedThroughTypeCheck = false;
......
......@@ -239,5 +239,7 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
{
return null;
}
internal override uint LocalScopeDepth => Binder.ExternalScope;
}
}
......@@ -63,6 +63,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return null;
}
internal override uint LocalScopeDepth => Binder.TopLevelScope;
internal override Symbol ContainingMemberOrLambda
{
get
......
......@@ -16,6 +16,7 @@ internal partial class LocalScopeBinder : Binder
private ImmutableArray<LocalSymbol> _locals;
private ImmutableArray<LocalFunctionSymbol> _localFunctions;
private ImmutableArray<LabelSymbol> _labels;
private readonly uint _localScopeDepth;
internal LocalScopeBinder(Binder next)
: this(next, next.Flags)
......@@ -25,6 +26,35 @@ internal LocalScopeBinder(Binder next)
internal LocalScopeBinder(Binder next, BinderFlags flags)
: base(next, flags)
{
var parentDepth = next.LocalScopeDepth;
if (parentDepth != Binder.TopLevelScope)
{
_localScopeDepth = parentDepth + 1;
}
else
{
//NOTE: TopLevel is special.
//For our purpose parameters and top level locals are on that level.
var parentScope = next;
while(parentScope != null)
{
if (parentScope is InMethodBinder || parentScope is WithLambdaParametersBinder)
{
_localScopeDepth = Binder.TopLevelScope;
break;
}
if (parentScope is LocalScopeBinder)
{
_localScopeDepth = Binder.TopLevelScope + 1;
break;
}
parentScope = parentScope.Next;
Debug.Assert(parentScope != null);
}
}
}
internal sealed override ImmutableArray<LocalSymbol> Locals
......@@ -338,6 +368,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return base.LookupLocalFunction(nameToken);
}
internal override uint LocalScopeDepth => _localScopeDepth;
internal override void LookupSymbolsInSingleBinder(
LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
......
......@@ -169,5 +169,7 @@ internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsF
{
throw ExceptionUtilities.Unreachable;
}
internal override uint LocalScopeDepth => Binder.TopLevelScope;
}
}
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpResources {
......@@ -1781,7 +1781,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to The parameter modifier &apos;{0}&apos; cannot be used with &apos;{1}&apos; .
/// Looks up a localized string similar to The parameter modifier &apos;{0}&apos; cannot be used with &apos;{1}&apos;.
/// </summary>
internal static string ERR_BadParameterModifiers {
get {
......@@ -2383,6 +2383,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to This combination of arguments to &apos;{0}&apos; is disallowed because it may expose variables referenced by parameter &apos;{1}&apos; outside of their declaration scope.
/// </summary>
internal static string ERR_CallArgMixing {
get {
return ResourceManager.GetString("ERR_CallArgMixing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Do not directly call your base class Finalize method. It is called automatically from your destructor..
/// </summary>
......@@ -3940,6 +3949,24 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use a result of &apos;{0}&apos; in this context because it may expose variables referenced by parameter &apos;{1}&apos; outside of their declaration scope.
/// </summary>
internal static string ERR_EscapeCall {
get {
return ResourceManager.GetString("ERR_EscapeCall", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use a member of result of &apos;{0}&apos; in this context because it may expose variables referenced by parameter &apos;{1}&apos; outside of their declaration scope.
/// </summary>
internal static string ERR_EscapeCall2 {
get {
return ResourceManager.GetString("ERR_EscapeCall2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A &apos;{0}&apos; character may only be escaped by doubling &apos;{0}{0}&apos; in an interpolated string..
/// </summary>
......@@ -3949,6 +3976,33 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use local &apos;{0}&apos; in this context because it may expose referenced variables outside of their declaration scope.
/// </summary>
internal static string ERR_EscapeLocal {
get {
return ResourceManager.GetString("ERR_EscapeLocal", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Expression cannot be used in this context because it may indirectly expose variables outside of their declaration scope.
/// </summary>
internal static string ERR_EscapeOther {
get {
return ResourceManager.GetString("ERR_EscapeOther", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A result of a stackalloc expression of type &apos;{0}&apos; cannot be used in this context because it may be exposed outside of the containing method.
/// </summary>
internal static string ERR_EscapeStackAlloc {
get {
return ResourceManager.GetString("ERR_EscapeStackAlloc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos;: event property must have both add and remove accessors.
/// </summary>
......@@ -6262,6 +6316,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>
......@@ -8341,24 +8404,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot return by reference a result of &apos;{0}&apos; because the argument passed to parameter &apos;{1}&apos; cannot be returned by reference.
/// </summary>
internal static string ERR_RefReturnCall {
get {
return ResourceManager.GetString("ERR_RefReturnCall", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot return by reference a member of result of &apos;{0}&apos; because the argument passed to parameter &apos;{1}&apos; cannot be returned by reference.
/// </summary>
internal static string ERR_RefReturnCall2 {
get {
return ResourceManager.GetString("ERR_RefReturnCall2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;await&apos; cannot be used in an expression containing a call to &apos;{0}&apos; because it returns by reference.
/// </summary>
......@@ -8430,18 +8475,20 @@ internal class CSharpResources {
return ResourceManager.GetString("ERR_RefReturnNonreturnableLocal2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot return a parameter by reference &apos;{0}&apos; because it is not a ref or out parameter.
/// </summary>
internal static string ERR_RefReturnParameter {
get {
internal static string ERR_RefReturnParameter
{
get
{
return ResourceManager.GetString("ERR_RefReturnParameter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot return a member of parameter &apos;{0}&apos; by reference because it is not a ref or out parameter.
/// Looks up a localized string similar to Cannot return by reference a member of parameter &apos;{0}&apos; because it is not a ref or out parameter.
/// </summary>
internal static string ERR_RefReturnParameter2 {
get {
......@@ -8459,7 +8506,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to A readonly field cannot be returned by reference.
/// Looks up a localized string similar to A readonly field cannot be returned by writable reference.
/// </summary>
internal static string ERR_RefReturnReadonly {
get {
......@@ -8468,7 +8515,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Members of readonly field &apos;{0}&apos; cannot be returned by reference.
/// Looks up a localized string similar to Members of readonly field &apos;{0}&apos; cannot be returned by writable reference.
/// </summary>
internal static string ERR_RefReturnReadonly2 {
get {
......@@ -8504,7 +8551,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Cannot return {0} &apos;{1}&apos; by reference because it is a readonly variable.
/// Looks up a localized string similar to Cannot return {0} &apos;{1}&apos; by writable reference because it is a readonly variable.
/// </summary>
internal static string ERR_RefReturnReadonlyNotField {
get {
......@@ -8513,7 +8560,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Members of {0} &apos;{1}&apos; cannot be returned by reference because it is a readonly variable.
/// Looks up a localized string similar to Members of {0} &apos;{1}&apos; cannot be returned by writable reference because it is a readonly variable.
/// </summary>
internal static string ERR_RefReturnReadonlyNotField2 {
get {
......@@ -8522,7 +8569,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to A static readonly field cannot be returned by reference.
/// Looks up a localized string similar to A static readonly field cannot be returned by writable reference.
/// </summary>
internal static string ERR_RefReturnReadonlyStatic {
get {
......@@ -8531,7 +8578,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Fields of static readonly field &apos;{0}&apos; cannot be returned by reference.
/// Looks up a localized string similar to Fields of static readonly field &apos;{0}&apos; cannot be returned by writable reference.
/// </summary>
internal static string ERR_RefReturnReadonlyStatic2 {
get {
......@@ -8540,20 +8587,20 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Cannot return &apos;{0}&apos; by reference because its receiver may not be returned by reference.
/// Looks up a localized string similar to Struct members cannot return &apos;this&apos; or other instance members by reference.
/// </summary>
internal static string ERR_RefReturnReceiver {
internal static string ERR_RefReturnStructThis {
get {
return ResourceManager.GetString("ERR_RefReturnReceiver", resourceCulture);
return ResourceManager.GetString("ERR_RefReturnStructThis", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Struct members cannot return &apos;this&apos; or other instance members by reference.
/// Looks up a localized string similar to Cannot return &apos;this&apos; by reference..
/// </summary>
internal static string ERR_RefReturnStructThis {
internal static string ERR_RefReturnThis {
get {
return ResourceManager.GetString("ERR_RefReturnStructThis", resourceCulture);
return ResourceManager.GetString("ERR_RefReturnThis", resourceCulture);
}
}
......
......@@ -1356,6 +1356,9 @@
<data name="ERR_AddrOnReadOnlyLocal" xml:space="preserve">
<value>Cannot take the address of a read-only local variable</value>
</data>
<data name="ERR_RefReturnThis" xml:space="preserve">
<value>Cannot return 'this' by reference.</value>
</data>
<data name="ERR_OverrideWithConstraints" xml:space="preserve">
<value>Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly</value>
</data>
......@@ -2369,7 +2372,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<value>Method '{0}' has a parameter modifier 'this' which is not on the first parameter</value>
</data>
<data name="ERR_BadParameterModifiers" xml:space="preserve">
<value> The parameter modifier '{0}' cannot be used with '{1}' </value>
<value> The parameter modifier '{0}' cannot be used with '{1}'</value>
</data>
<data name="ERR_BadTypeforThis" xml:space="preserve">
<value>The first parameter of an extension method cannot be of type '{0}'</value>
......@@ -2825,10 +2828,10 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<value>Cannot assign to a member of {0} '{1}' because it is a readonly variable</value>
</data>
<data name="ERR_RefReturnReadonlyNotField" xml:space="preserve">
<value>Cannot return {0} '{1}' by reference because it is a readonly variable</value>
<value>Cannot return {0} '{1}' by writable reference because it is a readonly variable</value>
</data>
<data name="ERR_RefReturnReadonlyNotField2" xml:space="preserve">
<value>Members of {0} '{1}' cannot be returned by reference because it is a readonly variable</value>
<value>Members of {0} '{1}' cannot be returned by writable reference because it is a readonly variable</value>
</data>
<data name="ERR_AssgReadonlyStatic2" xml:space="preserve">
<value>Fields of static readonly field '{0}' cannot be assigned to (except in a static constructor or a variable initializer)</value>
......@@ -4827,28 +4830,22 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>Cannot return fields of '{0}' by reference because it is a '{1}'</value>
</data>
<data name="ERR_RefReturnReadonly" xml:space="preserve">
<value>A readonly field cannot be returned by reference</value>
<value>A readonly field cannot be returned by writable reference</value>
</data>
<data name="ERR_RefReturnReadonlyStatic" xml:space="preserve">
<value>A static readonly field cannot be returned by reference</value>
<value>A static readonly field cannot be returned by writable reference</value>
</data>
<data name="ERR_RefReturnReadonly2" xml:space="preserve">
<value>Members of readonly field '{0}' cannot be returned by reference</value>
<value>Members of readonly field '{0}' cannot be returned by writable reference</value>
</data>
<data name="ERR_RefReturnReadonlyStatic2" xml:space="preserve">
<value>Fields of static readonly field '{0}' cannot be returned by reference</value>
</data>
<data name="ERR_RefReturnCall" xml:space="preserve">
<value>Cannot return by reference a result of '{0}' because the argument passed to parameter '{1}' cannot be returned by reference</value>
</data>
<data name="ERR_RefReturnCall2" xml:space="preserve">
<value>Cannot return by reference a member of result of '{0}' because the argument passed to parameter '{1}' cannot be returned by reference</value>
<value>Fields of static readonly field '{0}' cannot be returned by writable reference</value>
</data>
<data name="ERR_RefReturnParameter" xml:space="preserve">
<value>Cannot return a parameter by reference '{0}' because it is not a ref or out parameter</value>
</data>
<data name="ERR_RefReturnParameter2" xml:space="preserve">
<value>Cannot return a member of parameter '{0}' by reference because it is not a ref or out parameter</value>
<value>Cannot return by reference a member of parameter '{0}' because it is not a ref or out parameter</value>
</data>
<data name="ERR_RefReturnLocal" xml:space="preserve">
<value>Cannot return local '{0}' by reference because it is not a ref local</value>
......@@ -4856,12 +4853,30 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_RefReturnLocal2" xml:space="preserve">
<value>Cannot return a member of local '{0}' by reference because it is not a ref local</value>
</data>
<data name="ERR_RefReturnReceiver" xml:space="preserve">
<value>Cannot return '{0}' by reference because its receiver may not be returned by reference</value>
</data>
<data name="ERR_RefReturnStructThis" xml:space="preserve">
<value>Struct members cannot return 'this' or other instance members by reference</value>
</data>
<data name="ERR_EscapeOther" xml:space="preserve">
<value>Expression cannot be used in this context because it may indirectly expose variables outside of their declaration scope</value>
</data>
<data name="ERR_EscapeLocal" xml:space="preserve">
<value>Cannot use local '{0}' in this context because it may expose referenced variables outside of their declaration scope</value>
</data>
<data name="ERR_EscapeCall" xml:space="preserve">
<value>Cannot use a result of '{0}' in this context because it may expose variables referenced by parameter '{1}' outside of their declaration scope</value>
</data>
<data name="ERR_EscapeCall2" xml:space="preserve">
<value>Cannot use a member of result of '{0}' in this context because it may expose variables referenced by parameter '{1}' outside of their declaration scope</value>
</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 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_EscapeStackAlloc" xml:space="preserve">
<value>A result of a stackalloc expression of type '{0}' cannot be used in this context because it may be exposed outside of the containing method</value>
</data>
<data name="ERR_InitializeByValueVariableWithReference" xml:space="preserve">
<value>Cannot initialize a by-value variable with a reference</value>
</data>
......
......@@ -1411,8 +1411,8 @@ internal enum ErrorCode
ERR_RefReturnReadonlyStatic = 8161,
ERR_RefReturnReadonly2 = 8162,
ERR_RefReturnReadonlyStatic2 = 8163,
ERR_RefReturnCall = 8164,
ERR_RefReturnCall2 = 8165,
// ERR_RefReturnCall = 8164, we use more general ERR_EscapeCall now
// ERR_RefReturnCall2 = 8165, we use more general ERR_EscapeCall2 now
ERR_RefReturnParameter = 8166,
ERR_RefReturnParameter2 = 8167,
ERR_RefReturnLocal = 8168,
......@@ -1526,5 +1526,14 @@ internal enum ErrorCode
ERR_BadSpecialByRefIterator = 8518,
ERR_FieldAutoPropCantBeByRefLike = 8519,
ERR_StackAllocConversionNotPossible = 8520,
ERR_EscapeCall = 8521,
ERR_EscapeCall2 = 8522,
ERR_EscapeOther = 8523,
ERR_CallArgMixing = 8524,
ERR_MismatchedRefEscapeInTernary = 8525,
ERR_EscapeLocal = 8526,
ERR_EscapeStackAlloc = 8527,
ERR_RefReturnThis = 8528,
}
}
......@@ -3,6 +3,7 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -327,14 +328,17 @@ public object ConstantValue
get;
}
internal virtual bool IsReturnable
{
get
{
// by default all locals are returnable
return true;
}
}
/// <summary>
/// Returns the scope to which a local can "escape" ref assignments or other form of aliasing
/// Makes sense only for locals with formal scopes - i.e. source locals
/// </summary>
internal virtual uint RefEscapeScope => throw ExceptionUtilities.Unreachable;
/// <summary>
/// Returns the scope to which values of a local can "escape" via ordinary assignments
/// Makes sense only for ref-like locals with formal scopes - i.e. source locals
/// </summary>
internal virtual uint ValEscapeScope => throw ExceptionUtilities.Unreachable;
/// <summary>
/// When a local variable's type is inferred, it may not be used in the
......
......@@ -29,6 +29,18 @@ internal class SourceLocalSymbol : LocalSymbol
private readonly LocalDeclarationKind _declarationKind;
private TypeSymbol _type;
/// <summary>
/// Scope to which the local can "escape" via aliasing/ref assignment.
/// Not readonly because we can only know escape values after binding the initializer.
/// </summary>
protected uint _refEscapeScope;
/// <summary>
/// Scope to which the local's values can "escape" via ordinary assignemnts.
/// Not readonly because we can only know escape values after binding the initializer.
/// </summary>
protected uint _valEscapeScope;
private SourceLocalSymbol(
Symbol containingSymbol,
Binder scopeBinder,
......@@ -49,6 +61,14 @@ internal class SourceLocalSymbol : LocalSymbol
// create this eagerly as it will always be needed for the EnsureSingleDefinition
_locations = ImmutableArray.Create<Location>(identifierToken.GetLocation());
_refEscapeScope = this._refKind == RefKind.None ?
scopeBinder.LocalScopeDepth :
Binder.ExternalScope; // default to returnable, unless there is initializer
// we do not know the type yet.
// assume this is returnable in case we never get to know our type.
_valEscapeScope = Binder.ExternalScope;
}
/// <summary>
......@@ -213,7 +233,12 @@ internal override bool IsPinned
}
}
internal virtual void SetReturnable()
internal virtual void SetRefEscape(uint value)
{
throw ExceptionUtilities.Unreachable;
}
internal virtual void SetValEscape(uint value)
{
throw ExceptionUtilities.Unreachable;
}
......@@ -353,6 +378,11 @@ internal void SetType(TypeSymbol newType)
{
Interlocked.CompareExchange(ref _type, newType, null);
}
// to handle error self-referential cases we will default to the current scope
_valEscapeScope = _type.IsByRefLikeType ?
_scopeBinder.LocalScopeDepth :
Binder.ExternalScope;
}
/// <summary>
......@@ -467,11 +497,6 @@ private sealed class LocalWithInitializer : SourceLocalSymbol
/// </summary>
private EvaluatedConstant _constantTuple;
/// <summary>
/// Unfortunately we can only know a ref local is returnable after binding the initializer.
/// </summary>
private bool _returnable;
public LocalWithInitializer(
Symbol containingSymbol,
Binder scopeBinder,
......@@ -488,11 +513,8 @@ private sealed class LocalWithInitializer : SourceLocalSymbol
_initializer = initializer;
_initializerBinder = initializerBinder;
// byval locals are always returnable
// byref locals with initializers are assumed not returnable unless proven otherwise
// NOTE: if we assumed returnable, then self-referring initializer could result in
// a randomly changing returnability when initializer is bound concurrently.
_returnable = this.RefKind == RefKind.None;
// default to the current scope in case we need to handle self-referential error cases.
_refEscapeScope = _scopeBinder.LocalScopeDepth;
}
protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
......@@ -552,16 +574,31 @@ internal override ImmutableArray<Diagnostic> GetConstantValueDiagnostics(BoundEx
return _constantTuple == null ? ImmutableArray<Diagnostic>.Empty : _constantTuple.Diagnostics;
}
internal override void SetReturnable()
internal override void SetRefEscape(uint value)
{
Debug.Assert(value <= _refEscapeScope);
_refEscapeScope = value;
}
internal override void SetValEscape(uint value)
{
_returnable = true;
Debug.Assert(value <= _valEscapeScope);
_valEscapeScope = value;
}
internal override uint RefEscapeScope
{
get
{
return _refEscapeScope;
}
}
internal override bool IsReturnable
internal override uint ValEscapeScope
{
get
{
return _returnable;
return _valEscapeScope;
}
}
}
......
......@@ -435,6 +435,47 @@ static void M(in int arg1, in (int Alice, int Bob) arg2)
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "arg2.Alice").WithArguments("variable", "in (int Alice, int Bob)"));
}
[Fact]
public void ReadonlyParamCannotRefReturn()
{
var text = @"
class Program
{
static ref readonly int M1_baseline(in int arg1, in (int Alice, int Bob) arg2)
{
// valid
return ref arg1;
}
static ref readonly int M2_baseline(in int arg1, in (int Alice, int Bob) arg2)
{
// valid
return ref arg2.Alice;
}
static ref int M1(in int arg1, in (int Alice, int Bob) arg2)
{
return ref arg1;
}
static ref int M2(in int arg1, in (int Alice, int Bob) arg2)
{
return ref arg2.Alice;
}
}
";
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (18,20): error CS8410: Cannot return variable 'in int' by writable reference because it is a readonly variable
// return ref arg1;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "arg1").WithArguments("variable", "in int").WithLocation(18, 20),
// (23,20): error CS8411: Members of variable 'in (int Alice, int Bob)' cannot be returned by writable reference because it is a readonly variable
// return ref arg2.Alice;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField2, "arg2.Alice").WithArguments("variable", "in (int Alice, int Bob)").WithLocation(23, 20)
);
}
[Fact]
public void ReadonlyParamCannotAssignByref()
{
......@@ -522,12 +563,13 @@ class Program
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (10,24): error CS8406: Cannot use variable 'in int' as a ref or out value because it is a readonly variable
// (10,24): error CS8410: Cannot return variable 'in int' by writable reference because it is a readonly variable
// return ref arg1;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "arg1").WithArguments("variable", "in int"),
// (14,24): error CS8407: Members of variable 'in (int Alice, int Bob)' cannot be used as a ref or out value because it is a readonly variable
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "arg1").WithArguments("variable", "in int").WithLocation(10, 24),
// (14,24): error CS8411: Members of variable 'in (int Alice, int Bob)' cannot be returned by writable reference because it is a readonly variable
// return ref arg2.Alice;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField2, "arg2.Alice").WithArguments("variable", "in (int Alice, int Bob)"));
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField2, "arg2.Alice").WithArguments("variable", "in (int Alice, int Bob)").WithLocation(14, 24)
);
}
[Fact]
......@@ -640,12 +682,12 @@ class Program
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (12,28): error CS8406: Cannot use variable 'in int' as a ref or out value because it is a readonly variable
// (12,28): error CS8410: Cannot return variable 'in int' by writable reference because it is a readonly variable
// return ref arg11;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "arg11").WithArguments("variable", "in int").WithLocation(12, 28),
// (16,28): error CS8407: Members of variable 'in (int Alice, int Bob)' cannot be used as a ref or out value because it is a readonly variable
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "arg11").WithArguments("variable", "in int").WithLocation(12, 28),
// (16,28): error CS8411: Members of variable 'in (int Alice, int Bob)' cannot be returned by writable reference because it is a readonly variable
// return ref arg21.Alice;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField2, "arg21.Alice").WithArguments("variable", "in (int Alice, int Bob)").WithLocation(16, 28)
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField2, "arg21.Alice").WithArguments("variable", "in (int Alice, int Bob)").WithLocation(16, 28)
);
}
......
......@@ -632,10 +632,7 @@ public void Test3()
Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "this").WithArguments("this").WithLocation(32, 26),
// (37,26): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// TakesRef(ref this.x); // error
Diagnostic(ErrorCode.ERR_RefReadonly, "this.x").WithLocation(37, 26),
// (37,26): error CS1605: Cannot use 'this' as a ref or out value because it is read-only
// TakesRef(ref this.x); // error
Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "this.x").WithArguments("this").WithLocation(37, 26)
Diagnostic(ErrorCode.ERR_RefReadonly, "this.x").WithLocation(37, 26)
);
}
......@@ -1116,12 +1113,10 @@ private static int GetLength()
}
public static void Main()
{
Span<int> x = default;
{
for (int i = 0; i < 5; i++)
{
x = stackalloc int[GetLength()];
Span<int> x = stackalloc int[GetLength()];
Console.Write(x.Length);
}
}
......@@ -1129,37 +1124,35 @@ public static void Main()
CompileAndVerify(comp, expectedOutput: "12345", verify: false).VerifyIL("Test.Main", @"
{
// Code size 52 (0x34)
// Code size 44 (0x2c)
.maxstack 2
.locals init (System.Span<int> V_0, //x
int V_1, //i
.locals init (int V_0, //i
System.Span<int> V_1, //x
int V_2)
IL_0000: ldloca.s V_0
IL_0002: initobj ""System.Span<int>""
IL_0008: ldc.i4.0
IL_0009: stloc.1
IL_000a: br.s IL_002f
IL_000c: call ""int Test.GetLength()""
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: conv.u
IL_0014: ldc.i4.4
IL_0015: mul.ovf.un
IL_0016: localloc
IL_0018: ldloc.2
IL_0019: newobj ""System.Span<int>..ctor(void*, int)""
IL_001e: stloc.0
IL_001f: ldloca.s V_0
IL_0021: call ""int System.Span<int>.Length.get""
IL_0026: call ""void System.Console.Write(int)""
IL_002b: ldloc.1
IL_002c: ldc.i4.1
IL_002d: add
IL_002e: stloc.1
IL_002f: ldloc.1
IL_0030: ldc.i4.5
IL_0031: blt.s IL_000c
IL_0033: ret
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0027
IL_0004: call ""int Test.GetLength()""
IL_0009: stloc.2
IL_000a: ldloc.2
IL_000b: conv.u
IL_000c: ldc.i4.4
IL_000d: mul.ovf.un
IL_000e: localloc
IL_0010: ldloc.2
IL_0011: newobj ""System.Span<int>..ctor(void*, int)""
IL_0016: stloc.1
IL_0017: ldloca.s V_1
IL_0019: call ""int System.Span<int>.Length.get""
IL_001e: call ""void System.Console.Write(int)""
IL_0023: ldloc.0
IL_0024: ldc.i4.1
IL_0025: add
IL_0026: stloc.0
IL_0027: ldloc.0
IL_0028: ldc.i4.5
IL_0029: blt.s IL_0004
IL_002b: ret
}");
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
[CompilerTrait(CompilerFeature.RefConditionalOperator)]
public class CodeGenRefConditionalOperatorTests : CSharpTestBase
{
[Fact]
......@@ -625,12 +627,12 @@ static void Main()
var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (8,27): error CS1510: A ref or out value must be an assignable variable
// (8,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// (b? ref val1: ref 42) = 1;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "42").WithLocation(8, 27),
// (10,46): error CS1510: A ref or out value must be an assignable variable
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "42").WithLocation(8, 27),
// (10,46): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// ref var local = ref b? ref val1: ref 42;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "42").WithLocation(10, 46)
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "42").WithLocation(10, 46)
);
}
......@@ -661,9 +663,6 @@ static void Main()
// (15,27): error CS8168: Cannot return local 'local1' by reference because it is not a ref local
// return ref b? ref local1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local1").WithArguments("local1").WithLocation(15, 27),
// (15,39): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// return ref b? ref local1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(15, 39),
// (15,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref b? ref local1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "b? ref local1: ref local2").WithLocation(15, 20)
......@@ -698,9 +697,9 @@ static void Main()
// (14,37): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// return ref b? ref val1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 37),
// (14,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// (14,20): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// return ref b? ref val1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "b? ref val1: ref local2").WithLocation(14, 20)
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 20)
);
}
......@@ -737,9 +736,9 @@ struct S1
// (14,38): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// return ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 38),
// (14,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// (14,21): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// return ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "(b? ref val1: ref local2).x").WithLocation(14, 20)
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 21)
);
}
......@@ -774,9 +773,12 @@ struct S1
var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (15,20): error CS8157: Cannot return 'temp' by reference because it was initialized to a value that cannot be returned by reference
// return ref temp;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "temp").WithArguments("temp").WithLocation(15, 20)
// (14,46): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// ref var temp = ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 46),
// (14,29): error CS8525: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var temp = ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 29)
);
}
......@@ -871,9 +873,9 @@ static void Main()
var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (8,47): error CS1510: A ref or out value must be an assignable variable
// (8,47): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// System.Console.Write(b? ref val1: ref ()=>1);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "()=>1").WithLocation(8, 47)
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "()=>1").WithLocation(8, 47)
);
}
......
......@@ -322,18 +322,18 @@ class Program
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (12,28): error CS8406: Cannot use method 'Program.M()' as a ref or out value because it is a readonly variable
// (12,28): error CS8410: Cannot return method 'Program.M()' by writable reference because it is a readonly variable
// return ref M();
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "M()").WithArguments("method", "Program.M()").WithLocation(12, 28),
// (16,28): error CS8407: Members of method 'Program.M1()' cannot be used as a ref or out value because it is a readonly variable
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "M()").WithArguments("method", "Program.M()").WithLocation(12, 28),
// (16,28): error CS8411: Members of method 'Program.M1()' cannot be returned by writable reference because it is a readonly variable
// return ref M1().Alice;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField2, "M1().Alice").WithArguments("method", "Program.M1()").WithLocation(16, 28),
// (23,28): error CS8406: Cannot use property 'Program.P' as a ref or out value because it is a readonly variable
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField2, "M1().Alice").WithArguments("method", "Program.M1()").WithLocation(16, 28),
// (23,28): error CS8410: Cannot return property 'Program.P' by writable reference because it is a readonly variable
// return ref P;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "P").WithArguments("property", "Program.P").WithLocation(23, 28),
// (27,28): error CS8407: Members of property 'Program.P1' cannot be used as a ref or out value because it is a readonly variable
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "P").WithArguments("property", "Program.P").WithLocation(23, 28),
// (27,28): error CS8411: Members of property 'Program.P1' cannot be returned by writable reference because it is a readonly variable
// return ref P1.Alice;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField2, "P1.Alice").WithArguments("property", "Program.P1").WithLocation(27, 28)
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField2, "P1.Alice").WithArguments("property", "Program.P1").WithLocation(27, 28)
);
}
......@@ -563,15 +563,15 @@ class Program
// (11,30): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref M(ref local);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(11, 30),
// (11,24): error CS8164: Cannot return by reference a result of 'Program.M(ref int)' because the argument passed to parameter 'x' cannot be returned by reference
// (11,24): error CS8521: Cannot use a result of 'Program.M(ref int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref M(ref local);
Diagnostic(ErrorCode.ERR_RefReturnCall, "M(ref local)").WithArguments("Program.M(ref int)", "x").WithLocation(11, 24),
Diagnostic(ErrorCode.ERR_EscapeCall, "M(ref local)").WithArguments("Program.M(ref int)", "x").WithLocation(11, 24),
// (15,31): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref M1(out local).Alice;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(15, 31),
// (15,24): error CS8165: Cannot return by reference a member of result of 'Program.M1(out int)' because the argument passed to parameter 'x' cannot be returned by reference
// (15,24): error CS8522: Cannot use a member of result of 'Program.M1(out int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref M1(out local).Alice;
Diagnostic(ErrorCode.ERR_RefReturnCall2, "M1(out local)").WithArguments("Program.M1(out int)", "x").WithLocation(15, 24)
Diagnostic(ErrorCode.ERR_EscapeCall2, "M1(out local)").WithArguments("Program.M1(out int)", "x").WithLocation(15, 24)
);
}
......@@ -598,9 +598,9 @@ class Program
// (8,25): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref this[local];
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(8, 25),
// (8,24): error CS8164: Cannot return by reference a result of 'Program.this[in int]' because the argument passed to parameter 'x' cannot be returned by reference
// (8,20): error CS8521: Cannot use a result of 'Program.this[in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref this[local];
Diagnostic(ErrorCode.ERR_RefReturnCall, "[local]").WithArguments("Program.this[in int]", "x").WithLocation(8, 24)
Diagnostic(ErrorCode.ERR_EscapeCall, "this[local]").WithArguments("Program.this[in int]", "x").WithLocation(8, 20)
);
}
......@@ -625,9 +625,9 @@ class Program
// (6,25): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref this[42];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "42").WithLocation(6, 25),
// (6,24): error CS8164: Cannot return by reference a result of 'Program.this[in int]' because the argument passed to parameter 'x' cannot be returned by reference
// (6,20): error CS8521: Cannot use a result of 'Program.this[in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref this[42];
Diagnostic(ErrorCode.ERR_RefReturnCall, "[42]").WithArguments("Program.this[in int]", "x").WithLocation(6, 24)
Diagnostic(ErrorCode.ERR_EscapeCall, "this[42]").WithArguments("Program.this[in int]", "x").WithLocation(6, 20)
);
}
......@@ -705,9 +705,9 @@ class Program
// (6,22): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref M(42);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "42").WithLocation(6, 22),
// (6,20): error CS8164: Cannot return by reference a result of 'Program.M(in int)' because the argument passed to parameter 'x' cannot be returned by reference
// (6,20): error CS8521: Cannot use a result of 'Program.M(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref M(42);
Diagnostic(ErrorCode.ERR_RefReturnCall, "M(42)").WithArguments("Program.M(in int)", "x").WithLocation(6, 20)
Diagnostic(ErrorCode.ERR_EscapeCall, "M(42)").WithArguments("Program.M(in int)", "x").WithLocation(6, 20)
);
}
......@@ -729,9 +729,9 @@ class Program
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,20): error CS8164: Cannot return by reference a result of 'Program.M(in int)' because the argument passed to parameter 'x' cannot be returned by reference
// (6,20): error CS8521: Cannot use a result of 'Program.M(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref M();
Diagnostic(ErrorCode.ERR_RefReturnCall, "M()").WithArguments("Program.M(in int)", "x").WithLocation(6, 20)
Diagnostic(ErrorCode.ERR_EscapeCall, "M()").WithArguments("Program.M(in int)", "x").WithLocation(6, 20)
);
}
......@@ -757,9 +757,9 @@ class Program
// (7,22): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref M(b);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "b").WithLocation(7, 22),
// (7,20): error CS8164: Cannot return by reference a result of 'Program.M(in int)' because the argument passed to parameter 'x' cannot be returned by reference
// (7,20): error CS8521: Cannot use a result of 'Program.M(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref M(b);
Diagnostic(ErrorCode.ERR_RefReturnCall, "M(b)").WithArguments("Program.M(in int)", "x").WithLocation(7, 20)
Diagnostic(ErrorCode.ERR_EscapeCall, "M(b)").WithArguments("Program.M(in int)", "x").WithLocation(7, 20)
);
}
}
......
......@@ -3099,9 +3099,9 @@ public void M()
// (14,26): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref G(ref d.Length);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(14, 26),
// (14,20): error CS8164: Cannot return by reference a result of 'C.G(ref dynamic)' because the argument passed to parameter 'd' cannot be returned by reference
// (14,20): error CS8521: Cannot use a result of 'C.G(ref dynamic)' in this context because it may expose variables referenced by parameter 'd' outside of their declaration scope
// return ref G(ref d.Length);
Diagnostic(ErrorCode.ERR_RefReturnCall, "G(ref d.Length)").WithArguments("C.G(ref dynamic)", "d").WithLocation(14, 20)
Diagnostic(ErrorCode.ERR_EscapeCall, "G(ref d.Length)").WithArguments("C.G(ref dynamic)", "d").WithLocation(14, 20)
);
}
......
......@@ -157,17 +157,21 @@ namespace N.Goo;
emitResult.Diagnostics.Verify(
// (13,16): error CS1514: { expected
Diagnostic(ErrorCode.ERR_LbraceExpected, ";"),
// namespace N.Foo;
Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(13, 16),
// (13,17): error CS1513: } expected
Diagnostic(ErrorCode.ERR_RbraceExpected, ""),
// namespace N.Foo;
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(13, 17),
// (4,16): error CS0246: The type or namespace name 'Blah' could not be found (are you missing a using directive or an assembly reference?)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Blah").WithArguments("Blah"),
// public Blah field;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Blah").WithArguments("Blah").WithLocation(4, 16),
// (8,13): error CS0198: A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)
Diagnostic(ErrorCode.ERR_AssgReadonlyStatic, "ro"),
// (4,21): warning CS0649: Field 'N.X.field' is never assigned to, and will always have its default value null
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("N.X.field", "null"),
// (5,37): warning CS0414: The field 'N.X.ro' is assigned but its value is never used
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "ro").WithArguments("N.X.ro"));
// ro = 4;
Diagnostic(ErrorCode.ERR_AssgReadonlyStatic, "ro").WithLocation(8, 13),
// (4,21): warning CS0649: Field 'X.field' is never assigned to, and will always have its default value null
// public Blah field;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("N.X.field", "null").WithLocation(4, 21)
);
}
// Check that EmitMetadataOnly works
......
......@@ -5,9 +5,11 @@
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using System.Linq;
using Microsoft.CodeAnalysis.Test.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
[CompilerTrait(CompilerFeature.RefLocalsReturns)]
public class RefLocalsAndReturnsTests : CompilingTestBase
{
private static CSharpCompilation CreateCompilationRef(
......@@ -290,18 +292,18 @@ public struct S1
}";
var comp = CreateCompilationRef(text);
comp.VerifyDiagnostics(
// (13,30): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(13, 30),
// (18,24): error CS8168: Cannot return local 'ro' by reference because it is not a ref local
// return ref ro;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "ro").WithArguments("ro").WithLocation(18, 24),
// (23,30): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro.x;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(23, 30),
// (28,24): error CS8169: Cannot return a member of local 'ro' by reference because it is not a ref local
// return ref ro.x;
Diagnostic(ErrorCode.ERR_RefReturnLocal2, "ro").WithArguments("ro").WithLocation(28, 24)
// (13,30): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(13, 30),
// (18,24): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable'
// return ref ro;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(18, 24),
// (23,30): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro.x;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(23, 30),
// (28,24): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable'
// return ref ro.x;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(28, 24)
);
}
......@@ -515,27 +517,27 @@ static Test()
// (65,33): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// ref char temp = ref i1;
Diagnostic(ErrorCode.ERR_RefReadonly, "i1").WithLocation(65, 33),
// (68,24): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// (68,24): error CS8160: A readonly field cannot be returned by writable reference
// return ref i1;
Diagnostic(ErrorCode.ERR_RefReadonly, "i1").WithLocation(68, 24),
Diagnostic(ErrorCode.ERR_RefReturnReadonly, "i1").WithLocation(68, 24),
// (72,33): error CS1649: Members of readonly field 'Test.i2' cannot be used as a ref or out value (except in a constructor)
// ref char temp = ref i2.x;
Diagnostic(ErrorCode.ERR_RefReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(72, 33),
// (75,24): error CS1649: Members of readonly field 'Test.i2' cannot be used as a ref or out value (except in a constructor)
// (75,24): error CS8162: Members of readonly field 'Test.i2' cannot be returned by writable reference
// return ref i2.x;
Diagnostic(ErrorCode.ERR_RefReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(75, 24),
Diagnostic(ErrorCode.ERR_RefReturnReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(75, 24),
// (83,33): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "s1").WithLocation(83, 33),
// (86,24): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor)
// (86,24): error CS8161: A static readonly field cannot be returned by writable reference
// return ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "s1").WithLocation(86, 24),
Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic, "s1").WithLocation(86, 24),
// (90,33): error CS1651: Fields of static readonly field 'Test.s2' cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s2.x;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(90, 33),
// (93,24): error CS1651: Fields of static readonly field 'Test.s2' cannot be used as a ref or out value (except in a static constructor)
// (93,24): error CS8163: Fields of static readonly field 'Test.s2' cannot be returned by writable reference
// return ref s2.x;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(93, 24)
Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(93, 24)
);
}
......@@ -617,24 +619,24 @@ public class C
// (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local
// return ref Goo(ref M1);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32),
// (36,24): error CS8164: Cannot return by reference a result of 'Test.Goo<char>(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference
// (36,24): error CS8521: Cannot use a result of 'Test.Goo<char>(ref char)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M1);
Diagnostic(ErrorCode.ERR_RefReturnCall, "Goo(ref M1)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(36, 24),
Diagnostic(ErrorCode.ERR_EscapeCall, "Goo(ref M1)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(36, 24),
// (41,32): error CS8169: Cannot return a member of local 'M2' by reference because it is not a ref local
// return ref Goo(ref M2.x);
Diagnostic(ErrorCode.ERR_RefReturnLocal2, "M2").WithArguments("M2").WithLocation(41, 32),
// (41,24): error CS8164: Cannot return by reference a result of 'Test.Goo<char>(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference
// (41,24): error CS8521: Cannot use a result of 'Test.Goo<char>(ref char)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M2.x);
Diagnostic(ErrorCode.ERR_RefReturnCall, "Goo(ref M2.x)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(41, 24),
Diagnostic(ErrorCode.ERR_EscapeCall, "Goo(ref M2.x)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(41, 24),
// (46,32): error CS8168: Cannot return local 'M2' by reference because it is not a ref local
// return ref Goo(ref M2).x;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "M2").WithArguments("M2").WithLocation(46, 32),
// (46,24): error CS8165: Cannot return by reference a member of result of 'Test.Goo<Test.S1>(ref Test.S1)' because the argument passed to parameter 'arg' cannot be returned by reference
// (46,24): error CS8522: Cannot use a member of result of 'Test.Goo<Test.S1>(ref Test.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M2).x;
Diagnostic(ErrorCode.ERR_RefReturnCall2, "Goo(ref M2)").WithArguments("Test.Goo<Test.S1>(ref Test.S1)", "arg").WithLocation(46, 24),
// (58,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
Diagnostic(ErrorCode.ERR_EscapeCall2, "Goo(ref M2)").WithArguments("Test.Goo<Test.S1>(ref Test.S1)", "arg").WithLocation(46, 24),
// (58,24): error CS8528: Cannot return 'this' by reference.
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(58, 24)
Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithArguments("this").WithLocation(58, 24)
);
}
......@@ -903,15 +905,9 @@ 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),
// (17,46): error CS0266: Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?)
// char Moo3(ref char a, ref char b) => r;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "r").WithArguments("int", "char").WithLocation(17, 46),
// (7,18): warning CS8321: The local function 'Goo' is declared but never used
// ref char Goo(ref char a, ref char b) => ref a;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo").WithArguments("Goo").WithLocation(7, 18),
......@@ -926,7 +922,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")]
......@@ -1885,9 +1882,9 @@ class Program
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// (8,20): error CS8160: A readonly field cannot be returned by writable reference
// return ref i;
Diagnostic(ErrorCode.ERR_RefReadonly, "i").WithLocation(8, 20)
Diagnostic(ErrorCode.ERR_RefReturnReadonly, "i").WithLocation(8, 20)
);
}
......@@ -1979,12 +1976,13 @@ class Program
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS8912: Cannot return or assign a reference to parameter 'i' because it is not a ref or out parameter
// (8,26): error CS8166: Cannot return a parameter by reference 'i' because it is not a ref or out parameter
// return ref d(ref i, ref j, o);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(8, 26),
// (8,20): error CS8910: Cannot return or assign a reference to the result of 'D.Invoke(ref int, ref int, object)' because the argument passed to parameter 'i' cannot be returned or assigned by reference
// (8,20): error CS8521: Cannot use a result of 'D.Invoke(ref int, ref int, object)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref d(ref i, ref j, o);
Diagnostic(ErrorCode.ERR_RefReturnCall, "d(ref i, ref j, o)").WithArguments("D.Invoke(ref int, ref int, object)", "i").WithLocation(8, 20));
Diagnostic(ErrorCode.ERR_EscapeCall, "d(ref i, ref j, o)").WithArguments("D.Invoke(ref int, ref int, object)", "i").WithLocation(8, 20)
);
}
[Fact]
......@@ -2001,14 +1999,14 @@ class Program
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (7,26): error CS8914: Cannot return or assign a reference to local 'j' because it is not a ref local
// (7,26): error CS8168: Cannot return local 'j' by reference because it is not a ref local
// return ref M(ref j);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "j").WithArguments("j").WithLocation(7, 26),
// (7,20): error CS8910: Cannot return or assign a reference to the result of 'Program.M(ref int)' because the argument passed to parameter 'i' cannot be returned or assigned by reference
// (7,20): error CS8521: Cannot use a result of 'Program.M(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref M(ref j);
Diagnostic(ErrorCode.ERR_RefReturnCall, "M(ref j)").WithArguments("Program.M(ref int)", "i").WithLocation(7, 20));
Diagnostic(ErrorCode.ERR_EscapeCall, "M(ref j)").WithArguments("Program.M(ref int)", "i").WithLocation(7, 20)
);
}
[Fact]
......@@ -2044,9 +2042,9 @@ class Program
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,20): error CS8170: Struct members cannot return 'this' or other instance members by reference
// (6,20): error CS8528: Cannot return 'this' by reference.
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(6, 20)
Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithArguments("this").WithLocation(6, 20)
);
}
......
......@@ -720,13 +720,8 @@ void M()
Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "int").WithLocation(35, 18),
// (36,9): error CS1604: Cannot assign to 'this' because it is read-only
// this = null;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "this").WithArguments("this").WithLocation(36, 9),
// (6,23): warning CS0414: The field 'C.static_readonly' is assigned but its value is never used
// static readonly S static_readonly;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "static_readonly").WithArguments("C.static_readonly").WithLocation(6, 23),
// (8,18): warning CS0414: The field 'C.instance_readonly' is assigned but its value is never used
// readonly int instance_readonly;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "instance_readonly").WithArguments("C.instance_readonly").WithLocation(8, 18));
Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "this").WithArguments("this").WithLocation(36, 9)
);
}
[Fact]
......
......@@ -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)
);
}
......@@ -197,10 +200,10 @@ static void M3l(in SpanLike<string> ss)
{
}
// OK
// Not OK
static ref Span<string> M4(ref Span<string> ss) { return ref ss; }
// OK
// Not OK
static ref readonly Span<string> M5(ref Span<string> ss) => ref ss;
// Not OK
......@@ -217,7 +220,14 @@ static void M3l(in SpanLike<string> ss)
Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref TypedReference ss").WithArguments("System.TypedReference").WithLocation(39, 34),
// (39,12): error CS1599: Method or delegate cannot return type 'TypedReference'
// static ref TypedReference M1(ref TypedReference ss) => ref ss;
Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ref TypedReference").WithArguments("System.TypedReference").WithLocation(39, 12));
Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ref TypedReference").WithArguments("System.TypedReference").WithLocation(39, 12),
// (32,66): error CS8166: Cannot return a parameter by reference 'ss' because it is not a ref or out parameter
// static ref Span<string> M4(ref Span<string> ss) { return ref ss; }
Diagnostic(ErrorCode.ERR_RefReturnParameter, "ss").WithArguments("ss").WithLocation(32, 66),
// (35,69): error CS8166: Cannot return a parameter by reference 'ss' because it is not a ref or out parameter
// static ref readonly Span<string> M5(ref Span<string> ss) => ref ss;
Diagnostic(ErrorCode.ERR_RefReturnParameter, "ss").WithArguments("ss").WithLocation(35, 69)
);
}
[Fact]
......
......@@ -24,5 +24,6 @@ public enum CompilerFeature
DefaultLiteral,
AsyncMain,
PEVerifyCompat,
RefConditionalOperator,
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册