From 7884b578f464f8365675d8cf7277db0b9dc23103 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 15 Jul 2022 11:55:01 -0700 Subject: [PATCH 01/12] Support UnscopedRefAttribute --- .../Compiler Breaking Changes - DotNet 7.md | 25 +- .../Portable/Binder/Binder.ValueChecks.cs | 30 +- .../Portable/Binder/Binder_Expressions.cs | 4 +- .../Lowering/SynthesizedMethodBaseSymbol.cs | 2 +- .../SymbolDisplayVisitor.Members.cs | 6 +- .../MethodWellKnownAttributeData.cs | 16 + .../ParameterEarlyWellKnownAttributeData.cs | 15 + .../PropertyWellKnownAttributeData.cs | 16 + .../FunctionPointerParameterSymbol.cs | 3 +- .../Symbols/Metadata/PE/PEParameterSymbol.cs | 10 +- .../Portable/Symbols/ParameterSymbol.cs | 12 +- .../Symbols/SignatureOnlyParameterSymbol.cs | 3 +- .../Symbols/Source/ParameterHelpers.cs | 4 +- .../Source/SourceClonedParameterSymbol.cs | 3 +- .../Source/SourceComplexParameterSymbol.cs | 23 + ...berContainerSymbol_ImplementationChecks.cs | 2 +- .../SourceMethodSymbolWithAttributes.cs | 6 + .../Symbols/Source/SourceParameterSymbol.cs | 8 +- .../Source/SourceParameterSymbolBase.cs | 2 +- .../Source/SourcePropertySymbolBase.cs | 6 + .../Source/SourceSimpleParameterSymbol.cs | 2 + .../Symbols/Source/ThisParameterSymbol.cs | 30 +- .../Synthesized/SynthesizedParameterSymbol.cs | 8 +- .../Symbols/Wrapped/WrappedParameterSymbol.cs | 4 +- .../AttributeTests_CallerInfoAttributes.cs | 22 + .../AttributeTests_LifetimeAnnotation.cs | 2 +- .../Test/Semantic/Semantics/RefFieldTests.cs | 873 +++++++++++++++++- .../SymbolDisplay/SymbolDisplayTests.cs | 26 + .../Symbol/Symbols/MissingSpecialMember.cs | 2 + .../Core/Portable/MetadataReader/PEModule.cs | 5 + .../Attributes/AttributeDescription.cs | 1 + .../Core/Portable/WellKnownMember.cs | 1 + .../Core/Portable/WellKnownMembers.cs | 8 + src/Compilers/Core/Portable/WellKnownTypes.cs | 2 + .../Test/Utilities/CSharp/CSharpTestBase.cs | 9 + .../WellKnownTypeValidationTests.vb | 10 +- .../Symbols/ObjectIdLocalSymbol.cs | 2 +- 37 files changed, 1161 insertions(+), 42 deletions(-) diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 8df4598162ef7..52e464cce567d 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -128,15 +128,24 @@ static ref T ReturnOutParamByRef(out T t) } ``` -A possible workaround is to change the method signature to pass the parameter by `ref` instead. +Possible workarounds are: +1. Use `System.Diagnostics.CodeAnalysis.UnscopedRefAttribute` to mark the reference as unscoped. + ```csharp + static ref T ReturnOutParamByRef([UnscopedRef] out T t) + { + t = default; + return ref t; // ok + } + ``` -```csharp -static ref T ReturnRefParamByRef(ref T t) -{ - t = default; - return ref t; // ok -} -``` +1. Change the method signature to pass the parameter by `ref`. + ```csharp + static ref T ReturnRefParamByRef(ref T t) + { + t = default; + return ref t; // ok + } + ``` ## Method ref struct return escape analysis depends on ref escape of ref arguments diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 49db2a7a7cb27..728cbdc1751ba 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -782,7 +782,7 @@ private uint GetParameterValEscape(ParameterSymbol parameter) { if (UseUpdatedEscapeRules) { - return parameter.Scope == DeclarationScope.ValueScoped ? + return parameter.EffectiveScope == DeclarationScope.ValueScoped ? Binder.TopLevelScope : Binder.ExternalScope; } @@ -796,7 +796,7 @@ private uint GetParameterRefEscape(ParameterSymbol parameter) { if (UseUpdatedEscapeRules) { - return parameter.RefKind is RefKind.None || parameter.Scope != DeclarationScope.Unscoped ? Binder.TopLevelScope : Binder.ExternalScope; + return parameter.RefKind is RefKind.None || parameter.EffectiveScope != DeclarationScope.Unscoped ? Binder.TopLevelScope : Binder.ExternalScope; } else { @@ -1822,7 +1822,7 @@ bool considerParameter(ParameterSymbol? parameter) // SPEC: For a given argument `a` that is passed to parameter `p`: // SPEC: 1. ... // SPEC: 2. If `p` is `scoped` then `a` does not contribute *safe-to-escape* when considering arguments. - if (parameter?.Scope == DeclarationScope.ValueScoped) + if (parameter?.EffectiveScope == DeclarationScope.ValueScoped) { return false; } @@ -1909,7 +1909,7 @@ private static RefKind GetEffectiveRefKind( } } - scope = paramIndex >= 0 ? parameters[paramIndex].Scope : DeclarationScope.Unscoped; + scope = paramIndex >= 0 ? parameters[paramIndex].EffectiveScope : DeclarationScope.Unscoped; return effectiveRefKind; } @@ -2227,6 +2227,8 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres return ((BoundLocal)expr).LocalSymbol.RefEscapeScope; case BoundKind.ThisReference: + Debug.Assert(this.ContainingMember() is MethodSymbol { ThisParameter: not null }); + var thisref = (BoundThisReference)expr; // "this" is an RValue, unless in a struct. @@ -2235,6 +2237,15 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres break; } + if (UseUpdatedEscapeRules) + { + if (this.ContainingMember() is MethodSymbol { ThisParameter: var thisParameter } && + thisParameter.EffectiveScope == DeclarationScope.Unscoped) + { + return Binder.ExternalScope; + } + } + //"this" is not returnable by reference in a struct. // can ref escape to any other level return Binder.TopLevelScope; @@ -2481,6 +2492,8 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF return CheckLocalRefEscape(node, local, escapeTo, checkingReceiver, diagnostics); case BoundKind.ThisReference: + Debug.Assert(this.ContainingMember() is MethodSymbol { ThisParameter: not null }); + var thisref = (BoundThisReference)expr; // "this" is an RValue, unless in a struct. @@ -2492,6 +2505,15 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF //"this" is not returnable by reference in a struct. if (escapeTo == Binder.ExternalScope) { + if (UseUpdatedEscapeRules) + { + if (this.ContainingMember() is MethodSymbol { ThisParameter: var thisParameter } && + thisParameter.EffectiveScope == DeclarationScope.Unscoped) + { + // can ref escape to any other level + return true; + } + } Error(diagnostics, ErrorCode.ERR_RefReturnStructThis, node); return false; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 096834571c6e6..147c0d1229cd1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8846,8 +8846,8 @@ private MethodGroupResolution ResolveDefaultMethodGroup( } var parameters = method.Parameters; - var parameterScopes = parameters.Any(p => p.Scope != DeclarationScope.Unscoped) ? - parameters.SelectAsArray(p => p.Scope) : + var parameterScopes = parameters.Any(p => p.EffectiveScope != DeclarationScope.Unscoped) ? + parameters.SelectAsArray(p => p.EffectiveScope) : default; return GetMethodGroupOrLambdaDelegateType(node.Syntax, method.RefKind, method.ReturnTypeWithAnnotations, method.ParameterRefKinds, parameterScopes, method.ParameterTypesWithAnnotations); } diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index d7d406f635e22..60f032ab0c80a 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -136,7 +136,7 @@ private ImmutableArray MakeParameters() ordinal++, p.RefKind, p.Name, - p.Scope, + p.DeclaredScope, // the synthesized parameter doesn't need to have the same ref custom modifiers as the base refCustomModifiers: default, inheritAttributes ? p as SourceComplexParameterSymbolBase : null)); diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index 870861d9d9d7f..f70c7bcf0e6e2 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -612,7 +612,7 @@ void visitFunctionPointerSignature(IMethodSymbol symbol) foreach (var param in symbol.Parameters) { // https://github.com/dotnet/roslyn/issues/61647: Use public API. - Debug.Assert((param as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().Scope switch + Debug.Assert((param as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().EffectiveScope switch { null => true, DeclarationScope.Unscoped => param.RefKind != RefKind.Out, @@ -780,7 +780,7 @@ public override void VisitParameter(IParameterSymbol symbol) AddCustomModifiersIfNeeded(symbol.RefCustomModifiers, leadingSpace: false, trailingSpace: true); // https://github.com/dotnet/roslyn/issues/61647: Use public API. - if ((symbol as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().Scope == DeclarationScope.ValueScoped && + if ((symbol as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().EffectiveScope == DeclarationScope.ValueScoped && format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.IncludeScoped)) { AddKeyword(SyntaxKind.ScopedKeyword); @@ -1079,7 +1079,7 @@ private void AddParameterRefKindIfNeeded(IParameterSymbol symbol) if (format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeParamsRefOut)) { // https://github.com/dotnet/roslyn/issues/61647: Use public API. - if ((symbol as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().Scope == DeclarationScope.RefScoped && + if ((symbol as Symbols.PublicModel.ParameterSymbol)?.GetSymbol().EffectiveScope == DeclarationScope.RefScoped && symbol.RefKind != RefKind.Out && format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.IncludeScoped)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs index 5a4c0ad0ea706..e95f295b21e87 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs @@ -44,6 +44,22 @@ public bool HasSkipLocalsInitAttribute } } + private bool _hasUnscopedRefAttribute; + public bool HasUnscopedRefAttribute + { + get + { + VerifySealed(expected: true); + return _hasUnscopedRefAttribute; + } + set + { + VerifySealed(expected: false); + _hasUnscopedRefAttribute = value; + SetDataStored(); + } + } + private ImmutableArray _memberNotNullAttributeData = ImmutableArray.Empty; public void AddNotNullMember(string memberName) diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/ParameterEarlyWellKnownAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/ParameterEarlyWellKnownAttributeData.cs index 3bcfe343f2c40..317fd4b0754d1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/ParameterEarlyWellKnownAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/ParameterEarlyWellKnownAttributeData.cs @@ -11,5 +11,20 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// internal sealed class ParameterEarlyWellKnownAttributeData : CommonParameterEarlyWellKnownAttributeData { + private bool _hasUnscopedRefAttribute; + public bool HasUnscopedRefAttribute + { + get + { + VerifySealed(expected: true); + return _hasUnscopedRefAttribute; + } + set + { + VerifySealed(expected: false); + _hasUnscopedRefAttribute = value; + SetDataStored(); + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/PropertyWellKnownAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/PropertyWellKnownAttributeData.cs index 99d6a9fdab3bd..8993a1d8ff8f2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/PropertyWellKnownAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/PropertyWellKnownAttributeData.cs @@ -94,6 +94,22 @@ public bool HasSkipLocalsInitAttribute } } + private bool _hasUnscopedRefAttribute; + public bool HasUnscopedRefAttribute + { + get + { + VerifySealed(expected: true); + return _hasUnscopedRefAttribute; + } + set + { + VerifySealed(expected: false); + _hasUnscopedRefAttribute = value; + SetDataStored(); + } + } + private ImmutableArray _memberNotNullAttributeData = ImmutableArray.Empty; public void AddNotNullMember(string memberName) diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs index 281f146b53c4e..150a61e2d46d9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs @@ -29,7 +29,8 @@ public FunctionPointerParameterSymbol(TypeWithAnnotations typeWithAnnotations, R public override int Ordinal { get; } public override Symbol ContainingSymbol => _containingSymbol; public override ImmutableArray RefCustomModifiers { get; } - internal override DeclarationScope Scope => RefKind == RefKind.Out ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; + internal override DeclarationScope DeclaredScope => RefKind == RefKind.Out ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; + internal override DeclarationScope EffectiveScope => DeclaredScope; public override bool Equals(Symbol other, TypeCompareKind compareKind) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index 7bf85f26e74f1..5b51e168db927 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -294,7 +294,11 @@ private PEParameterSymbol( typeWithAnnotations = NullableTypeDecoder.TransformType(typeWithAnnotations, handle, moduleSymbol, accessSymbol: accessSymbol, nullableContext: nullableContext); typeWithAnnotations = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeWithAnnotations, handle, moduleSymbol); - if (_moduleSymbol.Module.HasLifetimeAnnotationAttribute(_handle, out var pair)) + if (_moduleSymbol.Module.HasUnscopedRefAttribute(_handle)) + { + scope = DeclarationScope.Unscoped; + } + else if (_moduleSymbol.Module.HasLifetimeAnnotationAttribute(_handle, out var pair)) { var scopeOpt = GetScope(refKind, typeWithAnnotations.Type, pair.IsRefScoped, pair.IsValueScoped); if (scopeOpt is null) @@ -978,7 +982,9 @@ public override ImmutableArray DeclaringSyntaxReferences } } - internal sealed override DeclarationScope Scope => _packedFlags.Scope; + internal sealed override DeclarationScope DeclaredScope => _packedFlags.Scope; + + internal sealed override DeclarationScope EffectiveScope => DeclaredScope; private static DeclarationScope? GetScope(RefKind refKind, TypeSymbol type, bool isRefScoped, bool isValueScoped) { diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index ccc647939ee3a..4bb025069b9e3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -415,7 +415,17 @@ internal sealed override ObsoleteAttributeData? ObsoleteAttributeData /// internal abstract bool HasInterpolatedStringHandlerArgumentError { get; } - internal abstract DeclarationScope Scope { get; } + /// + /// The declared scope. From source, this is from the scope keyword + /// and any implicit scope, ignoring any UnscopedRefAttribute. + /// + internal abstract DeclarationScope DeclaredScope { get; } + + /// + /// The effective scope. This is from the declared scope and any + /// UnscopedRefAttribute. + /// + internal abstract DeclarationScope EffectiveScope { get; } protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BogusType; diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs index 35f0b30166b6a..a0c8fc9055f66 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs @@ -48,7 +48,8 @@ public SignatureOnlyParameterSymbol( public override bool IsDiscard { get { return false; } } - internal override DeclarationScope Scope => DeclarationScope.Unscoped; + internal override DeclarationScope DeclaredScope => DeclarationScope.Unscoped; + internal override DeclarationScope EffectiveScope => DeclaredScope; #region Not used by MethodSignatureComparer diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 6ee4c2db96bac..1f12f2db1adfe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -310,7 +310,7 @@ internal static bool RequiresLifetimeAnnotationAttribute(ParameterSymbol paramet { Debug.Assert(!parameter.IsThis); - var scope = parameter.Scope; + var scope = parameter.DeclaredScope; if (scope == DeclarationScope.Unscoped) { return false; @@ -648,7 +648,7 @@ private static void ReportParameterErrors( diagnostics.Add(ErrorCode.ERR_MethodArgCantBeRefAny, parameterSyntax.Location, parameter.Type); } - if (parameter.Scope == DeclarationScope.ValueScoped && !parameter.Type.IsErrorTypeOrRefLikeType()) + if (parameter.DeclaredScope == DeclarationScope.ValueScoped && !parameter.Type.IsErrorTypeOrRefLikeType()) { diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, parameterSyntax.Location); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceClonedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceClonedParameterSymbol.cs index 39d5cb9912a68..7532cd0c65ab9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceClonedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceClonedParameterSymbol.cs @@ -58,7 +58,8 @@ internal override bool IsMetadataOptional } } - internal sealed override DeclarationScope Scope => _originalParam.Scope; + internal sealed override DeclarationScope DeclaredScope => _originalParam.DeclaredScope; + internal sealed override DeclarationScope EffectiveScope => _originalParam.EffectiveScope; internal override ConstantValue ExplicitDefaultConstantValue { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 3c121938a6918..637b2fd4ad5a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -198,6 +198,22 @@ internal bool HasEnumeratorCancellationAttribute #nullable enable + internal sealed override DeclarationScope EffectiveScope + { + get + { + var scope = DeclaredScope; + if (scope != DeclarationScope.Unscoped && + HasUnscopedRefAttribute) + { + return DeclarationScope.Unscoped; + } + return scope; + } + } + + private bool HasUnscopedRefAttribute => GetEarlyDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; + internal static SyntaxNode? GetDefaultValueSyntaxForIsNullableAnalysisEnabled(ParameterSyntax? parameterSyntax) => parameterSyntax?.Default?.Value; @@ -593,6 +609,13 @@ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAt { return EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DateTimeConstantAttribute, ref arguments); } + else if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.UnscopedRefAttribute)) + { + // We can't bind the attribute here because that might lead to a cycle. + // Instead, simply record that the attribute exists and bind later. + arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + return (null, null); + } else if (!IsOnPartialImplementation(arguments.AttributeSyntax)) { if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerLineNumberAttribute)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 1319cc53f55b5..355aa4969c23c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -1392,7 +1392,7 @@ internal static bool CheckValidScopedOverride( { var baseParameter = baseParameters[i]; var overrideParameter = overrideParameters[i + overrideParameterOffset]; - if (baseParameter.Scope != overrideParameter.Scope) + if (baseParameter.EffectiveScope != overrideParameter.EffectiveScope) { reportMismatchInParameterType(diagnostics, baseMethod, overrideMethod, overrideParameter, topLevel: true, extraArgument); hasErrors = true; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 020f765ada186..5ffda5426aeca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -570,6 +570,10 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut { DecodeUnmanagedCallersOnlyAttribute(ref arguments); } + else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) + { + arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + } else { var compilation = this.DeclaringCompilation; @@ -600,6 +604,8 @@ public override FlowAnalysisAnnotations FlowAnalysisAnnotations private static FlowAnalysisAnnotations DecodeFlowAnalysisAttributes(MethodWellKnownAttributeData attributeData) => attributeData?.HasDoesNotReturnAttribute == true ? FlowAnalysisAnnotations.DoesNotReturn : FlowAnalysisAnnotations.None; + internal bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; + private bool VerifyObsoleteAttributeAppliedToMethod( ref DecodeWellKnownAttributeArguments arguments, AttributeDescription description) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs index 18e250286f61b..733cf610feedc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs @@ -143,7 +143,7 @@ internal SourceParameterSymbol WithCustomModifiersAndParamsCore(TypeSymbol newTy this.SyntaxReference, newIsParams, this.IsExtensionMethodThis, - this.Scope); + this.DeclaredScope); } // Local functions should never have custom modifiers @@ -160,7 +160,7 @@ internal SourceParameterSymbol WithCustomModifiersAndParamsCore(TypeSymbol newTy this.SyntaxReference, newIsParams, this.IsExtensionMethodThis, - this.Scope); + this.DeclaredScope); } internal sealed override bool RequiresCompletion @@ -222,7 +222,9 @@ public sealed override RefKind RefKind } } - internal sealed override DeclarationScope Scope => _scope; + internal sealed override DeclarationScope DeclaredScope => _scope; + + internal abstract override DeclarationScope EffectiveScope { get; } public sealed override string Name { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs index 96700c3745f60..44c42f4f81581 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbolBase.cs @@ -101,7 +101,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r if (ParameterHelpers.RequiresLifetimeAnnotationAttribute(this)) { - AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeLifetimeAnnotationAttribute(this, Scope)); + AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeLifetimeAnnotationAttribute(this, DeclaredScope)); } if (type.Type.ContainsTupleNames()) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index f597228d91dec..09b0eba912153 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1313,6 +1313,10 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut MessageID.IDS_FeatureMemberNotNull.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); CSharpAttributeData.DecodeMemberNotNullWhenAttribute(ContainingType, ref arguments); } + else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) + { + arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + } } internal bool HasDisallowNull @@ -1369,6 +1373,8 @@ internal ImmutableArray MemberNotNullAttributeIfExists internal ImmutableArray MemberNotNullWhenAttributeIfExists => FindAttributes(AttributeDescription.MemberNotNullWhenAttribute); + internal bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; + private SourceAttributeData FindAttribute(AttributeDescription attributeDescription) => (SourceAttributeData)GetAttributes().First(a => a.IsTargetAttribute(this, attributeDescription)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs index aad570a7aaa04..b11b6b6489261 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceSimpleParameterSymbol.cs @@ -128,5 +128,7 @@ internal override ConstantValue DefaultValueFromAttributes { get { return ConstantValue.NotAvailable; } } + + internal override DeclarationScope EffectiveScope => DeclaredScope; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index f2daba205129c..9769c5bb51f8d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -172,6 +172,34 @@ internal override MarshalPseudoCustomAttributeData? MarshallingInformation internal override bool HasInterpolatedStringHandlerArgumentError => false; - internal override DeclarationScope Scope => ContainingType?.TypeKind != TypeKind.Struct ? DeclarationScope.Unscoped : DeclarationScope.RefScoped; + internal override DeclarationScope DeclaredScope + => _containingType.IsStructType() ? DeclarationScope.RefScoped : DeclarationScope.Unscoped; + + internal override DeclarationScope EffectiveScope + { + get + { + var scope = DeclaredScope; + if (scope != DeclarationScope.Unscoped && + hasUnscopedRefAttribute(_containingMethod, _containingType as NamedTypeSymbol)) + { + return DeclarationScope.Unscoped; + } + return scope; + + static bool hasUnscopedRefAttribute(MethodSymbol? containingMethod, NamedTypeSymbol? containingType) + { + if (containingMethod is SourceMethodSymbolWithAttributes { HasUnscopedRefAttribute: true }) + { + return true; + } + if (containingMethod?.AssociatedSymbol is SourcePropertySymbol { HasUnscopedRefAttribute: true }) + { + return true; + } + return false; + } + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 79a23c89a71fc..b136db708e8bc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -162,7 +162,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r if (ParameterHelpers.RequiresLifetimeAnnotationAttribute(this)) { - AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeLifetimeAnnotationAttribute(this, Scope)); + AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeLifetimeAnnotationAttribute(this, DeclaredScope)); } if (type.Type.ContainsTupleNames() && @@ -188,7 +188,9 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r internal override bool HasInterpolatedStringHandlerArgumentError => false; - internal sealed override DeclarationScope Scope => _scope; + internal sealed override DeclarationScope DeclaredScope => _scope; + + internal sealed override DeclarationScope EffectiveScope => DeclaredScope; } internal sealed class SynthesizedParameterSymbol : SynthesizedParameterSymbolBase @@ -251,7 +253,7 @@ internal static ImmutableArray DeriveParameters(MethodSymbol so oldParam.Ordinal, oldParam.RefKind, oldParam.Name, - oldParam.Scope, + oldParam.DeclaredScope, oldParam.RefCustomModifiers, baseParameterForAttributes: null)); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs index 9bb91786d346c..d9aafec74e7f1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs @@ -152,7 +152,9 @@ public override string GetDocumentationCommentXml(CultureInfo? preferredCulture return _underlyingParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } - internal sealed override DeclarationScope Scope => _underlyingParameter.Scope; + internal sealed override DeclarationScope DeclaredScope => _underlyingParameter.DeclaredScope; + + internal sealed override DeclarationScope EffectiveScope => _underlyingParameter.EffectiveScope; #endregion } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs index f9f3b86e81005..e1b0cf7967028 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs @@ -5818,5 +5818,27 @@ void M(int i, [CallerArgumentExpression(""i"")] in string s = ""default value"") CompileAndVerify(comp, expectedOutput: "1 + 1").VerifyDiagnostics(); } + + [Fact] + public void CallerArgumentExpression_Cycle() + { + string source = +@"namespace System.Runtime.CompilerServices +{ + public sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parameterName))] string parameterName) + { + ParameterName = parameterName; + } + public string ParameterName { get; } + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,51): error CS8964: The CallerArgumentExpressionAttribute may only be applied to parameters with default values + // public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parameterName))] string parameterName) + Diagnostic(ErrorCode.ERR_BadCallerArgumentExpressionParamWithoutDefaultValue, "CallerArgumentExpression").WithLocation(5, 51)); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs index 59bb3ecc163d4..304f4a32e61bd 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs @@ -223,7 +223,7 @@ static void Main() var method = comp.GetMember("A.F4"); Assert.Equal("void A.F4(ref scoped R r)", method.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped))); var parameter = method.Parameters[0]; - Assert.Equal(DeclarationScope.ValueScoped, parameter.Scope); + Assert.Equal(DeclarationScope.ValueScoped, parameter.DeclaredScope); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 9d945efed5318..1574ffbb6adff 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -7300,7 +7300,7 @@ static void Main() private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, DeclarationScope expectedScope) { Assert.Equal(expectedRefKind, parameter.RefKind); - Assert.Equal(expectedScope, parameter.Scope); + Assert.Equal(expectedScope, parameter.EffectiveScope); Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped)); var attribute = parameter.GetAttributes().FirstOrDefault(a => a.GetTargetAttributeSignatureIndex(parameter, AttributeDescription.LifetimeAnnotationAttribute) != -1); @@ -12642,5 +12642,876 @@ public void ScopedReserved_Alias_Escaped() Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @scoped = System.Int32;").WithLocation(1, 1) ); } + + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Method_01(string type) + { + var source = +$@"using System.Diagnostics.CodeAnalysis; +{type} S1 +{{ + private int _field; + public ref int GetField1() => ref _field; // 1 + [UnscopedRef] public ref int GetField2() => ref _field; +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (5,39): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref int GetField1() => ref _field; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 39)); + } + + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Method_02(string type) + { + var source = +$@"using System.Diagnostics.CodeAnalysis; +{type} S +{{ + ref S F1() + {{ + ref S s1 = ref this; + return ref s1; + }} + [UnscopedRef] ref S F2() + {{ + ref S s2 = ref this; + return ref s2; + }} +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (7,20): error CS8157: Cannot return 's1' by reference because it was initialized to a value that cannot be returned by reference + // return ref s1; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "s1").WithArguments("s1").WithLocation(7, 20)); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Method_03(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public struct S +{ + private T _t; + public ref T F1() => throw null; + [UnscopedRef] public ref T F2() => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1() + { + var s = new S(); + return ref s.F1(); + } + static ref int F2() + { + var s = new S(); + return ref s.F2(); // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + // https://github.com/dotnet/roslyn/issues/62791: Missing errors. + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_Property_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +struct S1 +{ + private int _field; + public ref int Property1 => ref _field; // 1 + [UnscopedRef] public ref int Property2 => ref _field; +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (5,37): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref int Property1 => ref _field; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 37)); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Property_02(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public struct S +{ + private T _t; + public ref T P1 => throw null; + [UnscopedRef] public ref T P2 => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1() + { + var s = new S(); + return ref s.P1; + } + static ref int F2() + { + var s = new S(); + return ref s.P2; // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + // https://github.com/dotnet/roslyn/issues/62791: Missing errors. + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] + [Fact] + public void UnscopedRefAttribute_RefRefStructParameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +class Program +{ + static ref R ReturnRefStructRef(bool b, ref R x, [UnscopedRef] ref R y) + { + if (b) + return ref x; // 1 + else + return ref y; + } +}"; + // https://github.com/dotnet/roslyn/issues/62691: An error should be reported for 'return ref x;'. + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + + var parameters = comp.GetMember("Program.ReturnRefStructRef").Parameters; + VerifyParameterSymbol(parameters[1], "ref R x", RefKind.Ref, DeclarationScope.Unscoped); // https://github.com/dotnet/roslyn/issues/62691: Should be DeclarationScope.RefScoped. + VerifyParameterSymbol(parameters[2], "ref R y", RefKind.Ref, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_RefRefStructParameter_02(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R +{ + public ref T F; + public R(ref T t) { F = ref t; } +} +public class A +{ + public ref T F1A(ref R r1) + { + throw null; + } + public ref T F2A(scoped ref R r2) + { + throw null; + } + public ref T F3A([UnscopedRef] ref R r3) + { + return ref r3.F; + } + public ref T F4A([UnscopedRef] scoped ref R r4) + { + return ref r4.F; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref int F1A() + { + int i = 1; + var r = new R(ref i); + return ref F1A(ref r); // 1 + } + ref int F2A() + { + int i = 2; + var r = new R(ref i); + return ref F2A(ref r); + } + ref int F3A() + { + int i = 3; + var r = new R(ref i); + return ref F3A(ref r); // 2 + } + ref int F4A() + { + int i = 4; + var r = new R(ref i); + return ref F4A(ref r); // 3 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8347: Cannot use a result of 'A.F1A(ref R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref r)").WithArguments("A.F1A(ref R)", "r1").WithLocation(7, 20), + // (7,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(7, 28), + // (19,20): error CS8347: Cannot use a result of 'A.F3A(ref R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(ref r); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref r)").WithArguments("A.F3A(ref R)", "r3").WithLocation(19, 20), + // (19,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F3A(ref r); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(19, 28), + // (25,20): error CS8347: Cannot use a result of 'A.F4A(ref R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope + // return ref F4A(ref r); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref r)").WithArguments("A.F4A(ref R)", "r4").WithLocation(25, 20), + // (25,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F4A(ref r); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(25, 28)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref R r3", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_OutParameter_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static ref int ReturnOut(bool b, out int x, [UnscopedRef] out int y) + { + x = 1; + y = 2; + if (b) + return ref x; // 1 + else + return ref y; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (9,24): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // return ref x; // 1 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(9, 24)); + + var parameters = comp.GetMember("Program.ReturnOut").Parameters; + VerifyParameterSymbol(parameters[1], "out System.Int32 x", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(parameters[2], "out System.Int32 y", RefKind.Out, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_OutParameter_02(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public class A +{ + public ref T F1A(out T t1) + { + throw null; + } + public ref T F2A(scoped out T t2) + { + throw null; + } + public ref T F3A([UnscopedRef] out T t3) + { + t3 = default; + return ref t3; + } + public ref T F4A([UnscopedRef] scoped out T t4) + { + t4 = default; + return ref t4; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref int F1B() + { + int i = 1; + return ref F1A(out i); + } + ref int F2B() + { + int i = 2; + return ref F2A(out i); + } + ref int F3B() + { + int i = 3; + return ref F3A(out i); // 1 + } + ref int F4B() + { + int i = 4; + return ref F4A(out i); // 2 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + // https://github.com/dotnet/roslyn/issues/62791: Missing errors. + comp.VerifyEmitDiagnostics(); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "out System.Int32 t1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "out System.Int32 t2", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "out System.Int32 t3", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "out System.Int32 t4", RefKind.Out, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_RefParameter(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public class A +{ + public ref T F1A(ref T t1) => ref t1; + public ref T F2A(scoped ref T t2) => throw null; + public ref T F3A([UnscopedRef] ref T t3) => ref t3; + public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref int F1B() + { + int i = 1; + return ref F1A(ref i); // 1 + } + ref int F2B() + { + int i = 2; + return ref F2A(ref i); + } + ref int F3B() + { + int i = 3; + return ref F3A(ref i); // 2 + } + ref int F4B() + { + int i = 4; + return ref F4A(ref i); // 3 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (6,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // return ref F1A(ref i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A.F1A(ref int)", "t1").WithLocation(6, 20), + // (6,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F1A(ref i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 28), + // (16,20): error CS8347: Cannot use a result of 'A.F3A(ref int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + // return ref F3A(ref i); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref i)").WithArguments("A.F3A(ref int)", "t3").WithLocation(16, 20), + // (16,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F3A(ref i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 28), + // (21,20): error CS8347: Cannot use a result of 'A.F4A(ref int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + // return ref F4A(ref i); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref i)").WithArguments("A.F4A(ref int)", "t4").WithLocation(21, 20), + // (21,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F4A(ref i); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(21, 28)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref System.Int32 t2", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref System.Int32 t3", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_InParameter(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public class A +{ + public ref readonly T F1A(in T t1) => ref t1; + public ref readonly T F2A(scoped in T t2) => throw null; + public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; + public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref readonly int F1B() + { + int i = 1; + return ref F1A(in i); // 1 + } + ref readonly int F2B() + { + int i = 2; + return ref F2A(in i); + } + ref readonly int F3B() + { + int i = 3; + return ref F3A(in i); // 2 + } + ref readonly int F4B() + { + int i = 4; + return ref F4A(in i); // 3 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (6,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // return ref F1A(in i); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A.F1A(in int)", "t1").WithLocation(6, 20), + // (6,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F1A(in i); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 27), + // (16,20): error CS8347: Cannot use a result of 'A.F3A(in int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + // return ref F3A(in i); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(in i)").WithArguments("A.F3A(in int)", "t3").WithLocation(16, 20), + // (16,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F3A(in i); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 27), + // (21,20): error CS8347: Cannot use a result of 'A.F4A(in int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + // return ref F4A(in i); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(in i)").WithArguments("A.F4A(in int)", "t4").WithLocation(21, 20), + // (21,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + // return ref F4A(in i); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(21, 27)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped in System.Int32 t2", RefKind.In, DeclarationScope.RefScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "in System.Int32 t3", RefKind.In, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, DeclarationScope.Unscoped); + } + + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_RefStructParameter(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R +{ + public ref T F; + public R(ref T t) { F = ref t; } +} +public class A +{ + public ref T F1A(R r1) + { + return ref r1.F; + } + public ref T F2A(scoped R r2) + { + throw null; + } + public ref T F3A([UnscopedRef] R r3) + { + return ref r3.F; + } + public ref T F4A([UnscopedRef] scoped R r4) + { + return ref r4.F; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class B : A +{ + ref int F1A() + { + int i = 1; + var r = new R(ref i); + return ref F1A(r); // 1 + } + ref int F2A() + { + int i = 2; + var r = new R(ref i); + return ref F2A(r); + } + ref int F3A() + { + int i = 3; + var r = new R(ref i); + return ref F3A(r); // 2 + } + ref int F4A() + { + int i = 4; + var r = new R(ref i); + return ref F4A(r); // 3 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // return ref F1A(r); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A.F1A(R)", "r1").WithLocation(7, 20), + // (7,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F1A(r); // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(7, 24), + // (19,20): error CS8347: Cannot use a result of 'A.F3A(R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(r); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(r)").WithArguments("A.F3A(R)", "r3").WithLocation(19, 20), + // (19,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F3A(r); // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(19, 24), + // (25,20): error CS8347: Cannot use a result of 'A.F4A(R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope + // return ref F4A(r); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(r)").WithArguments("A.F4A(R)", "r4").WithLocation(25, 20), + // (25,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + // return ref F4A(r); // 3 + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(25, 24)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped R r2", RefKind.None, DeclarationScope.ValueScoped); + VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "R r3", RefKind.None, DeclarationScope.Unscoped); + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "R r4", RefKind.None, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_Overrides() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +abstract class A +{ + internal abstract void F1(out T t); + internal abstract void F2([UnscopedRef] out T t); +} +class B1 : A +{ + internal override void F1(out int i) { i = 0; } + internal override void F2([UnscopedRef] out int i) { i = 0; } +} +class B2 : A +{ + internal override void F1([UnscopedRef] out int i) { i = 0; } // 1 + internal override void F2(out int i) { i = 0; } // 2 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (14,28): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // internal override void F1([UnscopedRef] out int i) { i = 0; } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 28), + // (15,28): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // internal override void F2(out int i) { i = 0; } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(15, 28)); + } + + [Fact] + public void UnscopedRefAttribute_Implementations() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +interface I +{ + void F1(out T t); + void F2([UnscopedRef] out T t); +} +class C1 : I +{ + public void F1(out int i) { i = 0; } + public void F2([UnscopedRef] out int i) { i = 0; } +} +class C2 : I +{ + public void F1([UnscopedRef] out int i) { i = 0; } // 1 + public void F2(out int i) { i = 0; } // 2 +} +class C3 : I +{ + void I.F1(out object o) { o = null; } + void I.F2([UnscopedRef] out object o) { o = null; } +} +class C4 : I +{ + void I.F1([UnscopedRef] out object o) { o = null; } // 3 + void I.F2(out object o) { o = null; } // 4 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (14,17): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // public void F1([UnscopedRef] out int i) { i = 0; } // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 17), + // (15,17): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. + // public void F2(out int i) { i = 0; } // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(15, 17), + // (24,20): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member. + // void I.F1([UnscopedRef] out object o) { o = null; } // 3 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("o").WithLocation(24, 20), + // (25,20): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member. + // void I.F2(out object o) { o = null; } // 4 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("o").WithLocation(25, 20)); + } + + [Fact] + public void UnscopedRefAttribute_Delegates() + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +delegate void D1(out T t); +delegate void D2([UnscopedRef] out T t); + +class Program +{ + static void Main() + { + D1 d1; + d1 = (out int i1) => { i1 = 1; }; + d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 + D2 d2; + d2 = (out object o1) => { o1 = 1; }; // 2 + d2 = ([UnscopedRef] out object o2) => { o2 = 2; }; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (12,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1'. + // d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i2) => { i2 = 2; }").WithArguments("i2", "D1").WithLocation(12, 14), + // (14,14): error CS8986: The 'scoped' modifier of parameter 'o1' doesn't match target 'D2'. + // d2 = (out object o1) => { o1 = 1; }; // 2 + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(out object o1) => { o1 = 1; }").WithArguments("o1", "D2").WithLocation(14, 14)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var lambdas = tree.GetRoot().DescendantNodes().OfType().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol()).ToArray(); + + VerifyParameterSymbol(lambdas[0].Parameters[0], "out System.Int32 i1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(lambdas[1].Parameters[0], "out System.Int32 i2", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(lambdas[2].Parameters[0], "out System.Object o1", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_Cycle() + { + var source = +@"namespace System.Diagnostics.CodeAnalysis +{ + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; } + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,38): error CS7036: There is no argument given that corresponds to the required formal parameter 'i' of 'UnscopedRefAttribute.UnscopedRefAttribute(out int)' + // public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; } + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("i", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(out int)").WithLocation(5, 38)); + } + + [Fact] + public void UnscopedRefAttribute_UnexpectedConstructorArgument() + { + var sourceA = +@"namespace System.Diagnostics.CodeAnalysis +{ + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute(bool b) { } + } +}"; + var sourceB = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static ref int F1([UnscopedRef] out int i1) + { + i1 = 0; + return ref i1; + } + static ref int F2([UnscopedRef(true)] out int i2) + { + i2 = 0; + return ref i2; + } + static ref int F3() + { + int i3; + return ref F1(out i3); + } + static ref int F4() + { + int i4; + return ref F2(out i4); + } +}"; + var comp = CreateCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics( + // (4,24): error CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'UnscopedRefAttribute.UnscopedRefAttribute(bool)' + // static ref int F1([UnscopedRef] out int i1) + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("b", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(bool)").WithLocation(4, 24), + // (12,20): error CS8166: Cannot return a parameter by reference 'i2' because it is not a ref parameter + // return ref i2; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "i2").WithArguments("i2").WithLocation(12, 20)); + } + + [Fact] + public void UnscopedRefAttribute_InvalidConstructorArgument() + { + var sourceA = +@"namespace System.Diagnostics.CodeAnalysis +{ + public sealed class UnscopedRefAttribute : Attribute + { + public UnscopedRefAttribute(bool b) { } + } +}"; + var sourceB = +@"using System.Diagnostics.CodeAnalysis; +class Program +{ + static bool F1() + { + return true; + } + static ref int F2([UnscopedRef(F1())] out int i) + { + i = 0; + return ref i; + } +}"; + var comp = CreateCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics( + // (8,36): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // static ref int F2([UnscopedRef(F1())] out int i) + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "F1()").WithLocation(8, 36), + // (11,20): error CS8166: Cannot return a parameter by reference 'i' because it is not a ref parameter + // return ref i; + Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(11, 20)); + } + + [Fact] + public void UnscopedRefAttribute_ScopeRefAttribute() + { + var sourceA = +@".class private System.Diagnostics.CodeAnalysis.UnscopedRefAttribute extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class private System.Runtime.CompilerServices.LifetimeAnnotationAttribute extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor(bool isRefScoped, bool isValueScoped) cil managed { ret } +} +.class public A +{ + .method public static int32& NoAttributes([out] int32& i) + { + ldnull + throw + } + .method public static int32& ScopedRefOnly([out] int32& i) + { + .param [1] + .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) + ldnull + throw + } + .method public static int32& UnscopedRefOnly([out] int32& i) + { + .param [1] + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + ldnull + throw + } + .method public static int32& ScopedRefAndUnscopedRef([out] int32& i) + { + .param [1] + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.LifetimeAnnotationAttribute::.ctor(bool, bool) = ( 01 00 01 00 00 00 ) // LifetimeAnnotationAttribute(isRefScoped: true, isValueScoped: false) + ldnull + throw + } +} +"; + var refA = CompileIL(sourceA); + + var sourceB = +@"class Program +{ + static ref int F1() + { + int i; + return ref A.NoAttributes(out i); + } + static ref int F2() + { + int i; + return ref A.ScopedRefOnly(out i); + } + static ref int F3() + { + int i; + return ref A.UnscopedRefOnly(out i); // 1 + } + static ref int F4() + { + int i; + return ref A.ScopedRefAndUnscopedRef(out i); // 2 + } +}"; + var comp = CreateCompilation(sourceB, new[] { refA }); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp); + + var typeA = comp.GetMember("A"); + VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.RefScoped); + VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "out System.Int32 i", RefKind.Out, DeclarationScope.Unscoped); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index 11b98e31faa0f..acdb596eacbc5 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -8313,6 +8313,32 @@ unsafe class Program "delegate*"); } + [Fact] + public void ScopedParameter_04() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +class Program +{ + static void F1(out int i1, [UnscopedRef] out int i2) => throw null; + static void F2(ref R r1, [UnscopedRef] ref R r2) => throw null; +}"; + + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + + var format = SymbolDisplayFormat.TestFormat. + WithParameterOptions(SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeParamsRefOut). + WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeScoped); + + Verify(comp.GetMember("Program.F1").ToDisplayParts(format), + "void Program.F1(out System.Int32 i1, out System.Int32 i2)"); + + Verify(comp.GetMember("Program.F2").ToDisplayParts(format), + "void Program.F2(ref R r1, ref R r2)"); + } + [Fact] public void ScopedLocal() { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index e61298854268a..2663942e3fed6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -617,6 +617,7 @@ public void AllWellKnownTypes() case WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute: case WellKnownType.System_MemoryExtensions: case WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute: + case WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute: // Not yet in the platform. continue; case WellKnownType.Microsoft_CodeAnalysis_Runtime_Instrumentation: @@ -981,6 +982,7 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T: case WellKnownMember.System_MemoryExtensions__AsSpan_String: case WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor: + case WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor: // Not yet in the platform. continue; case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile: diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 6117c5f32428d..6e5c81f1e1d75 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1099,6 +1099,11 @@ internal bool HasLifetimeAnnotationAttribute(EntityHandle token, out (bool IsRef return TryExtractValueFromAttribute(info.Handle, out value, CrackBoolAndBoolInAttributeValue); } + internal bool HasUnscopedRefAttribute(EntityHandle token) + { + return FindTargetAttribute(token, AttributeDescription.UnscopedRefAttribute).HasValue; + } + internal bool HasTupleElementNamesAttribute(EntityHandle token, out ImmutableArray tupleElementNames) { var info = FindTargetAttribute(token, AttributeDescription.TupleElementNamesAttribute); diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs index abe6c5d039722..981b05de4cb83 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs @@ -478,5 +478,6 @@ static AttributeDescription() internal static readonly AttributeDescription RequiredMemberAttribute = new AttributeDescription("System.Runtime.CompilerServices", "RequiredMemberAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription SetsRequiredMembersAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "SetsRequiredMembersAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription CompilerFeatureRequiredAttribute = new AttributeDescription("System.Runtime.CompilerServices", "CompilerFeatureRequiredAttribute", s_signatures_HasThis_Void_String_Only); + internal static readonly AttributeDescription UnscopedRefAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "UnscopedRefAttribute", s_signatures_HasThis_Void_Only); } } diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index e32700fdbd918..838912eb28468 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -529,6 +529,7 @@ internal enum WellKnownMember System_MemoryExtensions__AsSpan_String, System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor, System_MissingMethodException__ctor, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 66117afc0bbae..8704273e8ce7a 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3640,6 +3640,13 @@ static WellKnownMembers() 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, + + // System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 0, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type // System_MissingMethodException__ctor (byte)MemberFlags.Constructor, // Flags @@ -4103,6 +4110,7 @@ static WellKnownMembers() "SequenceEqual", // System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T "AsSpan", // System_MemoryExtensions__AsSpan_String ".ctor", // System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute_ctor + ".ctor", // System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor ".ctor", // System_MissingMethodException__ctor }; diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index 41bf3dc7e746d..32fd6e2934d34 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -323,6 +323,7 @@ internal enum WellKnownType System_MemoryExtensions, System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, + System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, System_MissingMethodException, @@ -640,6 +641,7 @@ internal static class WellKnownTypes "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", "System.MemoryExtensions", "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", + "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", "System.MissingMethodException", }; diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 43b4045dd195c..605774c03c366 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -625,6 +625,15 @@ public UnmanagedCallersOnlyAttribute() { } } }"; + protected const string UnscopedRefAttributeDefinition = +@"namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)] + public sealed class UnscopedRefAttribute : Attribute + { + } +}"; + protected const string RequiredMemberAttribute = @" namespace System.Runtime.CompilerServices { diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 200cfb8e6ecf0..ed202ed8d29b1 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -552,6 +552,7 @@ End Namespace WellKnownType.System_MemoryExtensions, WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, WellKnownType.System_MemoryExtensions ' Not available on all platforms. Continue For @@ -623,7 +624,8 @@ End Namespace WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, WellKnownType.System_MemoryExtensions, WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, - WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute + WellKnownType.System_Runtime_CompilerServices_LifetimeAnnotationAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute ' Not available on all platforms. Continue For Case WellKnownType.ExtSentinel @@ -719,7 +721,8 @@ End Namespace WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, WellKnownMember.System_MemoryExtensions__AsSpan_String, - WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, @@ -871,7 +874,8 @@ End Namespace WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, WellKnownMember.System_MemoryExtensions__AsSpan_String, - WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_UnscopedRefAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs index 830898802cdf2..a9a75c0c859ab 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/ObjectIdLocalSymbol.cs @@ -77,7 +77,7 @@ internal override BoundExpression GetAddress(BoundPseudoVariable variable) method.Name, m => method.TypeParameters.SelectAsArray(t => (TypeParameterSymbol)new SimpleTypeParameterSymbol(m, t.Ordinal, t.Name)), m => m.TypeParameters[0], // return type is <>T& - m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.Scope, p.RefCustomModifiers))); + m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.DeclaredScope, p.RefCustomModifiers))); var local = variable.LocalSymbol; return InvokeGetMethod(method.Construct(local.Type), variable.Syntax, local.Name); } From 8dfbaae335871bafc5a81f33f21bf7d989d46982 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 28 Jul 2022 16:29:18 -0700 Subject: [PATCH 02/12] Misc. --- .../Test/Semantic/Semantics/RefFieldTests.cs | 190 +++++++++++++++++- 1 file changed, 182 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 1574ffbb6adff..73d9fc6f7aa4c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -13217,7 +13217,7 @@ ref int F4A() } [Fact] - public void UnscopedRefAttribute_Overrides() + public void UnscopedRefAttribute_Overrides_01() { var source = @"using System.Diagnostics.CodeAnalysis; @@ -13248,7 +13248,61 @@ class B2 : A } [Fact] - public void UnscopedRefAttribute_Implementations() + public void UnscopedRefAttribute_Overrides_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +abstract class A +{ + internal abstract void F1(ref T t); + internal abstract void F2([UnscopedRef] ref T t); +} +class B1 : A +{ + internal override void F1(ref int i) { } + internal override void F2([UnscopedRef] ref int i) { } +} +class B2 : A +{ + internal override void F1([UnscopedRef] ref int i) { } + internal override void F2(ref int i) { } +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_Overrides_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ +} +abstract class A +{ + internal abstract void F1(ref R r); + internal abstract void F2([UnscopedRef] ref R r); +} +class B1 : A +{ + internal override void F1(ref R r) { } + internal override void F2([UnscopedRef] ref R r) { } +} +class B2 : A +{ + internal override void F1([UnscopedRef] ref R r) { } // 1 + internal override void F2(ref R r) { } // 2 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62691: Expected errors should be reported when 'ref R' is considered 'scoped ref'. + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_Implementations_01() { var source = @"using System.Diagnostics.CodeAnalysis; @@ -13295,14 +13349,86 @@ class C4 : I } [Fact] - public void UnscopedRefAttribute_Delegates() + public void UnscopedRefAttribute_Implementations_02() { var source = @"using System.Diagnostics.CodeAnalysis; +interface I +{ + void F1(ref T t); + void F2([UnscopedRef] ref T t); +} +class C1 : I +{ + public void F1(ref int i) { } + public void F2([UnscopedRef] ref int i) { } +} +class C2 : I +{ + public void F1([UnscopedRef] ref int i) { } // 1 + public void F2(ref int i) { } // 2 +} +class C3 : I +{ + void I.F1(ref object o) { } + void I.F2([UnscopedRef] ref object o) { } +} +class C4 : I +{ + void I.F1([UnscopedRef] ref object o) { } // 3 + void I.F2(ref object o) { } // 4 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + } + [Fact] + public void UnscopedRefAttribute_Implementations_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ +} +interface I +{ + void F1(ref R r); + void F2([UnscopedRef] ref R r); +} +class C1 : I +{ + public void F1(ref R r) { } + public void F2([UnscopedRef] ref R r) { } +} +class C2 : I +{ + public void F1([UnscopedRef] ref R r) { } // 1 + public void F2(ref R r) { } // 2 +} +class C3 : I +{ + void I.F1(ref R r) { } + void I.F2([UnscopedRef] ref R r) { } +} +class C4 : I +{ + void I.F1([UnscopedRef] ref R r) { } // 3 + void I.F2(ref R r) { } // 4 +} +"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62691: Expected errors should be reported when 'ref R' is considered 'scoped ref'. + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_Delegates_01() + { + var source = +@"using System.Diagnostics.CodeAnalysis; delegate void D1(out T t); delegate void D2([UnscopedRef] out T t); - class Program { static void Main() @@ -13317,12 +13443,12 @@ static void Main() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (12,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1'. + // (10,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1'. // d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i2) => { i2 = 2; }").WithArguments("i2", "D1").WithLocation(12, 14), - // (14,14): error CS8986: The 'scoped' modifier of parameter 'o1' doesn't match target 'D2'. + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i2) => { i2 = 2; }").WithArguments("i2", "D1").WithLocation(10, 14), + // (12,14): error CS8986: The 'scoped' modifier of parameter 'o1' doesn't match target 'D2'. // d2 = (out object o1) => { o1 = 1; }; // 2 - Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(out object o1) => { o1 = 1; }").WithArguments("o1", "D2").WithLocation(14, 14)); + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(out object o1) => { o1 = 1; }").WithArguments("o1", "D2").WithLocation(12, 14)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -13334,6 +13460,54 @@ static void Main() VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, DeclarationScope.Unscoped); } + [Fact] + public void UnscopedRefAttribute_Delegates_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +delegate void D1(ref T t); +delegate void D2([UnscopedRef] ref T t); +class Program +{ + static void Main() + { + D1 d1; + d1 = (ref int i1) => { }; + d1 = ([UnscopedRef] ref int i2) => { }; + D2 d2; + d2 = (ref object o1) => { }; + d2 = ([UnscopedRef] ref object o2) => { }; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnscopedRefAttribute_Delegates_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R { } +delegate void D1(ref R r); +delegate void D2([UnscopedRef] ref R r); +class Program +{ + static void Main() + { + D1 d1; + d1 = (ref R r1) => { }; + d1 = ([UnscopedRef] ref R r2) => { }; // 1 + D2 d2; + d2 = (ref R r1) => { }; // 2 + d2 = ([UnscopedRef] ref R r2) => { }; + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62691: Expected errors should be reported when 'ref R' is considered 'scoped ref'. + comp.VerifyDiagnostics(); + } + [Fact] public void UnscopedRefAttribute_Cycle() { From 90dff6a4574896f7915f5e8f186beec0196280d7 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 28 Jul 2022 21:11:29 -0700 Subject: [PATCH 03/12] Address feedback --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../Symbols/MethodSymbolExtensions.cs | 8 + .../SourceMethodSymbolWithAttributes.cs | 9 +- .../Source/SourcePropertySymbolBase.cs | 20 +- .../Symbols/Source/ThisParameterSymbol.cs | 4 +- .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Test/Semantic/Semantics/RefFieldTests.cs | 234 +++++++++++++++++- 20 files changed, 332 insertions(+), 12 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index f2fbdd8911381..7fc07c1469424 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7205,4 +7205,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Types and aliases cannot be named 'scoped'. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 05b7a32e2c1ee..c130cad40e288 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2111,6 +2111,7 @@ internal enum ErrorCode ERR_CannotMatchOnINumberBase = 9060, ERR_MisplacedScoped = 9061, ERR_ScopedTypeNameDisallowed = 9062, + ERR_UnscopedRefAttributeUnsupportedMethod = 9063, #endregion diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index a194aea394fcc..413a9e308c56c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -217,5 +217,13 @@ internal static CSharpSyntaxNode ExtractReturnTypeSyntax(this MethodSymbol metho return (CSharpSyntaxNode)CSharpSyntaxTree.Dummy.GetRoot(); } + + internal static bool IsValidUnscopedRefAttributeTarget(this MethodSymbol method) + { + return !method.IsStatic && + method.ContainingType?.IsStructType() == true && + !method.IsConstructor() && + !method.IsInitOnly; + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 5ffda5426aeca..80e483f462458 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -572,7 +572,14 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) { - arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + if (this.IsValidUnscopedRefAttributeTarget()) + { + arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + } + else + { + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, arguments.AttributeSyntaxOpt.Location); + } } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 4d7ca568921df..363bbaaec4267 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1315,7 +1315,25 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) { - arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + if (this.IsValidUnscopedRefAttributeTarget()) + { + arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + } + else + { + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, arguments.AttributeSyntaxOpt.Location); + } + } + } + + private bool IsValidUnscopedRefAttributeTarget() + { + return isNullOrValidAccessor(_getMethod) && + isNullOrValidAccessor(_setMethod); + + static bool isNullOrValidAccessor(MethodSymbol? accessor) + { + return accessor is null || accessor.IsValidUnscopedRefAttributeTarget(); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index 9769c5bb51f8d..d76db838414ef 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -181,13 +181,13 @@ internal override DeclarationScope EffectiveScope { var scope = DeclaredScope; if (scope != DeclarationScope.Unscoped && - hasUnscopedRefAttribute(_containingMethod, _containingType as NamedTypeSymbol)) + hasUnscopedRefAttribute(_containingMethod)) { return DeclarationScope.Unscoped; } return scope; - static bool hasUnscopedRefAttribute(MethodSymbol? containingMethod, NamedTypeSymbol? containingType) + static bool hasUnscopedRefAttribute(MethodSymbol? containingMethod) { if (containingMethod is SourceMethodSymbolWithAttributes { HasUnscopedRefAttribute: true }) { diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index b009aa8742a86..06e5dd9dbb707 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1572,6 +1572,11 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. {0} vyžaduje funkci kompilátoru {1}, což tato verze kompilátoru C# nepodporuje. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 0b57395eb50c7..5e56985868f00 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1572,6 +1572,11 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' erfordert die Compilerfunktion '{1}', die von dieser Version des C#-Compilers nicht unterstützt wird. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index fa09c09c3822a..ac1324def137a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1572,6 +1572,11 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requiere la característica del compilador '{1}', que no es compatible con esta versión del compilador de C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 1abd33a14f021..15755783c4270 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1572,6 +1572,11 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' nécessite la fonctionnalité de compilateur '{1}', qui n’est pas prise en charge par cette version du compilateur C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 367e9626e8393..88c2f8d5b19de 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1572,6 +1572,11 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' richiede la funzionalità del compilatore '{1}', che non è supportata da questa versione del compilatore C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 1128c3ca900b7..0bbe78dfc02eb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1572,6 +1572,11 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' にはコンパイラ機能 '{1}' が必要ですが、このバージョンのC## コンパイラではサポートされていません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 6792a71260d8c..252c86eab85bb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1572,6 +1572,11 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}'에는 이 버전의 C # 컴파일러에서 지원되지 않는 컴파일러 기능 '{1}'이(가) 필요합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index cbd9a7e9dda3c..6ece6a383af5b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1572,6 +1572,11 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. „{0}” wymaga funkcji kompilatora „{1}”, która nie jest obsługiwana przez tę wersję kompilatora języka C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index e97227e174e19..6cfd597fb7b52 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1572,6 +1572,11 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requer o recurso de compilador '{1}', o que não é suportado por esta versão do compilador de C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index f64cfb57740bf..917546d89bced 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1572,6 +1572,11 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. Для "{0}" требуется функция компилятора "{1}", которая не поддерживается в этой версии компилятора C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 832a9b9a13c4e..6bebd10ec8668 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1572,6 +1572,11 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}', C# derleyicisinin bu sürümü tarafından desteklenmeyen '{1}' derleyici özelliğini gerektirir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 7b2aca9973b9c..9cbd68d67af46 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1572,6 +1572,11 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' 需要编译器功能 '{1}',此版本的 C# 编译器不支持此功能。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2c32044926414..493f09f99da2f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1572,6 +1572,11 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. + + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 21a6887e00d9a..e1ef5c11cb7ae 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -12728,6 +12728,224 @@ static ref int F2() comp.VerifyEmitDiagnostics(); } + [Fact] + public void UnscopedRefAttribute_Property_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +struct S +{ + [UnscopedRef] object P1 { get; } + [UnscopedRef] object P2 { get; set; } + [UnscopedRef] object P3 { get; init; } // 1 + object P5 + { + [UnscopedRef] get; + [UnscopedRef] set; + } + object P6 + { + [UnscopedRef] get; + [UnscopedRef] init; // 2 + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); + comp.VerifyDiagnostics( + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] object P3 { get; init; } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(6, 6), + // (15,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] init; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(15, 10)); + } + + [Theory] + [InlineData("struct")] + [InlineData("ref struct")] + public void UnscopedRefAttribute_Accessor_01(string type) + { + var source = +$@"using System.Diagnostics.CodeAnalysis; +{type} S +{{ + private T _t; + ref T P1 + {{ + get => ref _t; // 1 + }} + ref T P2 + {{ + [UnscopedRef] + get => ref _t; + }} +}}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (7,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // get => ref _t; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 20)); + } + + [Fact] + public void UnscopedRefAttribute_Accessor_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public ref T F; +} +struct A +{ + R this[int i] + { + get { return default; } + set { value.F = ref this; } // 1 + } +} +struct B +{ + R this[int i] + { + get { return default; } + [UnscopedRef] + set { value.F = ref this; } + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (11,15): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // set { value.F = ref this; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 15)); + } + + [Fact] + public void UnscopedRefAttribute_Accessor_03() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public ref T F; +} +struct A +{ + R this[int i] + { + get { return default; } + init { value.F = ref this; } // 1 + } +} +struct B +{ + R this[int i] + { + get { return default; } + [UnscopedRef] + init { value.F = ref this; } // 2 + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); + comp.VerifyDiagnostics( + // (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // init { value.F = ref this; } // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), + // (19,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(19, 10), + // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // init { value.F = ref this; } // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); + } + + [Fact] + public void UnscopedRefAttribute_Constructor() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +ref struct R +{ + public ref T F; +} +struct A +{ + A(R r) + { + r.F = ref this; // 1 + } +} +struct B +{ + [UnscopedRef] + B(R r) + { + r.F = ref this; // 2 + } +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 1 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9), + // (15,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(15, 6), + // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. + // r.F = ref this; // 2 + Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); + } + + [Fact] + public void UnscopedRefAttribute_StaticMembers() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +struct S +{ + [UnscopedRef] static S() { } // 1 + [UnscopedRef] static object F() => null; // 2 + [UnscopedRef] static object P => null; // 3 +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] static S() { } // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(4, 6), + // (5,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] static object F() => null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(5, 6), + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] static object P => null; // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(6, 6)); + } + + [Fact] + public void UnscopedRefAttribute_OtherTypes() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +class C +{ + [UnscopedRef] object F1() => null; // 1 +} +record R +{ + [UnscopedRef] object F2() => null; // 2 +} +record struct S +{ + [UnscopedRef] object F3() => null; +}"; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] object F1() => null; // 1 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(4, 6), + // (8,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // [UnscopedRef] object F2() => null; // 2 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(8, 6)); + } + [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] [Fact] public void UnscopedRefAttribute_RefRefStructParameter_01() @@ -12791,25 +13009,25 @@ public ref T F4A([UnscopedRef] scoped ref R r4) var sourceB = @"class B : A { - ref int F1A() + ref int F1B() { int i = 1; var r = new R(ref i); return ref F1A(ref r); // 1 } - ref int F2A() + ref int F2B() { int i = 2; var r = new R(ref i); return ref F2A(ref r); } - ref int F3A() + ref int F3B() { int i = 3; var r = new R(ref i); return ref F3A(ref r); // 2 } - ref int F4A() + ref int F4B() { int i = 4; var r = new R(ref i); @@ -13113,25 +13331,25 @@ public ref T F4A([UnscopedRef] scoped R r4) var sourceB = @"class B : A { - ref int F1A() + ref int F1B() { int i = 1; var r = new R(ref i); return ref F1A(r); // 1 } - ref int F2A() + ref int F2B() { int i = 2; var r = new R(ref i); return ref F2A(r); } - ref int F3A() + ref int F3B() { int i = 3; var r = new R(ref i); return ref F3A(r); // 2 } - ref int F4A() + ref int F4B() { int i = 4; var r = new R(ref i); From 9a33cb6a11bc2e9765e65fba5f4d3700efe8720b Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 29 Jul 2022 06:57:47 -0700 Subject: [PATCH 04/12] Fix tests --- src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index a338a2240b4c6..48af018455ae9 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2212,6 +2212,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_CannotMatchOnINumberBase: case ErrorCode.ERR_MisplacedScoped: case ErrorCode.ERR_ScopedTypeNameDisallowed: + case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement From 76936289d2323450d8422eef761dce7380ba245b Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 29 Jul 2022 07:38:13 -0700 Subject: [PATCH 05/12] Report error if parameter is not implicitly scoped --- .../CSharp/Portable/CSharpResources.resx | 5 +- .../CSharp/Portable/Errors/ErrorCode.cs | 3 +- .../CSharp/Portable/Errors/ErrorFacts.cs | 3 +- .../Source/SourceComplexParameterSymbol.cs | 21 ++ .../SourceMethodSymbolWithAttributes.cs | 2 +- .../Source/SourcePropertySymbolBase.cs | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 7 +- .../Portable/xlf/CSharpResources.de.xlf | 7 +- .../Portable/xlf/CSharpResources.es.xlf | 7 +- .../Portable/xlf/CSharpResources.fr.xlf | 7 +- .../Portable/xlf/CSharpResources.it.xlf | 7 +- .../Portable/xlf/CSharpResources.ja.xlf | 7 +- .../Portable/xlf/CSharpResources.ko.xlf | 7 +- .../Portable/xlf/CSharpResources.pl.xlf | 7 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 7 +- .../Portable/xlf/CSharpResources.ru.xlf | 7 +- .../Portable/xlf/CSharpResources.tr.xlf | 7 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 7 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 7 +- .../Test/Semantic/Semantics/RefFieldTests.cs | 209 ++++++++++-------- 20 files changed, 230 insertions(+), 106 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 7fc07c1469424..0355eb21f2c44 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7205,7 +7205,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Types and aliases cannot be named 'scoped'. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index c130cad40e288..5400bca99718b 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2111,7 +2111,8 @@ internal enum ErrorCode ERR_CannotMatchOnINumberBase = 9060, ERR_MisplacedScoped = 9061, ERR_ScopedTypeNameDisallowed = 9062, - ERR_UnscopedRefAttributeUnsupportedMethod = 9063, + ERR_UnscopedRefAttributeUnsupportedMember = 9063, + ERR_UnscopedRefAttributeUnsupportedParameter = 9064, #endregion diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 48af018455ae9..d2373225dc44d 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2212,7 +2212,8 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_CannotMatchOnINumberBase: case ErrorCode.ERR_MisplacedScoped: case ErrorCode.ERR_ScopedTypeNameDisallowed: - case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod: + case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember: + case ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 637b2fd4ad5a4..b826b27741b6d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -815,6 +815,27 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut { DecodeInterpolatedStringHandlerArgumentAttribute(ref arguments, diagnostics, index); } + else if (attribute.IsTargetAttribute(this, AttributeDescription.UnscopedRefAttribute)) + { + if (!this.IsValidUnscopedRefAttributeTarget()) + { + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, arguments.AttributeSyntaxOpt.Location); + } + } + } + + private bool IsValidUnscopedRefAttributeTarget() + { + switch (RefKind) + { + case RefKind.Out: + return true; + case RefKind.Ref: + var type = Type; + return type is null || type.IsErrorTypeOrRefLikeType(); + default: + return false; + } } private static bool? DecodeMaybeNullWhenOrNotNullWhenOrDoesNotReturnIfAttribute(AttributeDescription description, CSharpAttributeData attribute) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 80e483f462458..7af64872b8e03 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -578,7 +578,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, arguments.AttributeSyntaxOpt.Location); } } else diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 363bbaaec4267..8fa57278100da 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1321,7 +1321,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, arguments.AttributeSyntaxOpt.Location); } } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 06e5dd9dbb707..66a5c6c33592c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1572,11 +1572,16 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. {0} vyžaduje funkci kompilátoru {1}, což tato verze kompilátoru C# nepodporuje. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 5e56985868f00..8357fe44b3861 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1572,11 +1572,16 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' erfordert die Compilerfunktion '{1}', die von dieser Version des C#-Compilers nicht unterstützt wird. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index ac1324def137a..1f50c8dde7517 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1572,11 +1572,16 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requiere la característica del compilador '{1}', que no es compatible con esta versión del compilador de C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 15755783c4270..c78b20dd29fe8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1572,11 +1572,16 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' nécessite la fonctionnalité de compilateur '{1}', qui n’est pas prise en charge par cette version du compilateur C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 88c2f8d5b19de..0f1310a1bcad6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1572,11 +1572,16 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' richiede la funzionalità del compilatore '{1}', che non è supportata da questa versione del compilatore C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 0bbe78dfc02eb..ed499cd77a0b3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1572,11 +1572,16 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' にはコンパイラ機能 '{1}' が必要ですが、このバージョンのC## コンパイラではサポートされていません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 252c86eab85bb..39cb7ce8815cb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1572,11 +1572,16 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}'에는 이 버전의 C # 컴파일러에서 지원되지 않는 컴파일러 기능 '{1}'이(가) 필요합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 6ece6a383af5b..32abdd594b9d8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1572,11 +1572,16 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. „{0}” wymaga funkcji kompilatora „{1}”, która nie jest obsługiwana przez tę wersję kompilatora języka C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 6cfd597fb7b52..88cf7d174516c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1572,11 +1572,16 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requer o recurso de compilador '{1}', o que não é suportado por esta versão do compilador de C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 917546d89bced..2e9cd82f6e398 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1572,11 +1572,16 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. Для "{0}" требуется функция компилятора "{1}", которая не поддерживается в этой версии компилятора C#. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 6bebd10ec8668..875329faeb5ff 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1572,11 +1572,16 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}', C# derleyicisinin bu sürümü tarafından desteklenmeyen '{1}' derleyici özelliğini gerektirir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 9cbd68d67af46..98fa64cf125b7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1572,11 +1572,16 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' 需要编译器功能 '{1}',此版本的 C# 编译器不支持此功能。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 493f09f99da2f..f9a87fc279e00 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1572,11 +1572,16 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. - + UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index e1ef5c11cb7ae..c7808744b172f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -12753,10 +12753,10 @@ object P6 comp.VerifyDiagnostics( // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] object P3 { get; init; } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(6, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(6, 6), // (15,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] init; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(15, 10)); } [Theory] @@ -12852,7 +12852,7 @@ R this[int i] Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), // (19,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(19, 10), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(19, 10), // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); @@ -12889,7 +12889,7 @@ struct B Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9), // (15,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(15, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(15, 6), // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // r.F = ref this; // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); @@ -12910,13 +12910,13 @@ [UnscopedRef] static S() { } // 1 comp.VerifyDiagnostics( // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] static S() { } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(4, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(4, 6), // (5,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] static object F() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(5, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(5, 6), // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] static object P => null; // 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(6, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(6, 6)); } [Fact] @@ -12940,10 +12940,10 @@ record struct S comp.VerifyDiagnostics( // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] object F1() => null; // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(4, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(4, 6), // (8,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. // [UnscopedRef] object F2() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethod, "UnscopedRef").WithLocation(8, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(8, 6)); } [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] @@ -13156,11 +13156,10 @@ ref int F4B() VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "out System.Int32 t4", RefKind.Out, DeclarationScope.Unscoped); } - [CombinatorialData] - [Theory] - public void UnscopedRefAttribute_RefParameter(bool useCompilationReference) + [Fact] + public void UnscopedRefAttribute_RefParameter() { - var sourceA = + var source = @"using System.Diagnostics.CodeAnalysis; public class A { @@ -13168,13 +13167,8 @@ public class A public ref T F2A(scoped ref T t2) => throw null; public ref T F3A([UnscopedRef] ref T t3) => ref t3; public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; -}"; - var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B : A +} +class B : A { ref int F1B() { @@ -13197,26 +13191,32 @@ ref int F4B() return ref F4A(ref i); // 3 } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // (6,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref T F3A([UnscopedRef] ref T t3) => ref t3; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 23), + // (7,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 23), + // (14,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope // return ref F1A(ref i); // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A.F1A(ref int)", "t1").WithLocation(6, 20), - // (6,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A.F1A(ref int)", "t1").WithLocation(14, 20), + // (14,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F1A(ref i); // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 28), - // (16,20): error CS8347: Cannot use a result of 'A.F3A(ref int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 28), + // (24,20): error CS8347: Cannot use a result of 'A.F3A(ref int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope // return ref F3A(ref i); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref i)").WithArguments("A.F3A(ref int)", "t3").WithLocation(16, 20), - // (16,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref i)").WithArguments("A.F3A(ref int)", "t3").WithLocation(24, 20), + // (24,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F3A(ref i); // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 28), - // (21,20): error CS8347: Cannot use a result of 'A.F4A(ref int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 28), + // (29,20): error CS8347: Cannot use a result of 'A.F4A(ref int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope // return ref F4A(ref i); // 3 - Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref i)").WithArguments("A.F4A(ref int)", "t4").WithLocation(21, 20), - // (21,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref i)").WithArguments("A.F4A(ref int)", "t4").WithLocation(29, 20), + // (29,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F4A(ref i); // 3 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(21, 28)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 28)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, DeclarationScope.Unscoped); @@ -13225,11 +13225,10 @@ ref int F4B() VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, DeclarationScope.Unscoped); } - [CombinatorialData] - [Theory] - public void UnscopedRefAttribute_InParameter(bool useCompilationReference) + [Fact] + public void UnscopedRefAttribute_InParameter() { - var sourceA = + var source = @"using System.Diagnostics.CodeAnalysis; public class A { @@ -13237,13 +13236,8 @@ public class A public ref readonly T F2A(scoped in T t2) => throw null; public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; -}"; - var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B : A +} +class B : A { ref readonly int F1B() { @@ -13266,26 +13260,32 @@ ref readonly int F4B() return ref F4A(in i); // 3 } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope + // (6,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 32), + // (7,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 32), + // (14,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope // return ref F1A(in i); // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A.F1A(in int)", "t1").WithLocation(6, 20), - // (6,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A.F1A(in int)", "t1").WithLocation(14, 20), + // (14,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F1A(in i); // 1 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 27), - // (16,20): error CS8347: Cannot use a result of 'A.F3A(in int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 27), + // (24,20): error CS8347: Cannot use a result of 'A.F3A(in int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope // return ref F3A(in i); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(in i)").WithArguments("A.F3A(in int)", "t3").WithLocation(16, 20), - // (16,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(in i)").WithArguments("A.F3A(in int)", "t3").WithLocation(24, 20), + // (24,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F3A(in i); // 2 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 27), - // (21,20): error CS8347: Cannot use a result of 'A.F4A(in int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 27), + // (29,20): error CS8347: Cannot use a result of 'A.F4A(in int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope // return ref F4A(in i); // 3 - Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(in i)").WithArguments("A.F4A(in int)", "t4").WithLocation(21, 20), - // (21,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(in i)").WithArguments("A.F4A(in int)", "t4").WithLocation(29, 20), + // (29,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local // return ref F4A(in i); // 3 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(21, 27)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 27)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, DeclarationScope.Unscoped); @@ -13294,11 +13294,10 @@ ref readonly int F4B() VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, DeclarationScope.Unscoped); } - [CombinatorialData] - [Theory] - public void UnscopedRefAttribute_RefStructParameter(bool useCompilationReference) + [Fact] + public void UnscopedRefAttribute_RefStructParameter() { - var sourceA = + var source = @"using System.Diagnostics.CodeAnalysis; public ref struct R { @@ -13323,13 +13322,8 @@ public ref T F4A([UnscopedRef] scoped R r4) { return ref r4.F; } -}"; - var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); - comp.VerifyEmitDiagnostics(); - var refA = AsReference(comp, useCompilationReference); - - var sourceB = -@"class B : A +} +class B : A { ref int F1B() { @@ -13356,26 +13350,32 @@ ref int F4B() return ref F4A(r); // 3 } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (7,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // (17,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref T F3A([UnscopedRef] R r3) + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(17, 23), + // (21,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public ref T F4A([UnscopedRef] scoped R r4) + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(21, 23), + // (32,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope // return ref F1A(r); // 1 - Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A.F1A(R)", "r1").WithLocation(7, 20), - // (7,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A.F1A(R)", "r1").WithLocation(32, 20), + // (32,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope // return ref F1A(r); // 1 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(7, 24), - // (19,20): error CS8347: Cannot use a result of 'A.F3A(R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(32, 24), + // (44,20): error CS8347: Cannot use a result of 'A.F3A(R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope // return ref F3A(r); // 2 - Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(r)").WithArguments("A.F3A(R)", "r3").WithLocation(19, 20), - // (19,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(r)").WithArguments("A.F3A(R)", "r3").WithLocation(44, 20), + // (44,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope // return ref F3A(r); // 2 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(19, 24), - // (25,20): error CS8347: Cannot use a result of 'A.F4A(R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(44, 24), + // (50,20): error CS8347: Cannot use a result of 'A.F4A(R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope // return ref F4A(r); // 3 - Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(r)").WithArguments("A.F4A(R)", "r4").WithLocation(25, 20), - // (25,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(r)").WithArguments("A.F4A(R)", "r4").WithLocation(50, 20), + // (50,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope // return ref F4A(r); // 3 - Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(25, 24)); + Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(50, 24)); var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R r1", RefKind.None, DeclarationScope.Unscoped); @@ -13437,7 +13437,16 @@ internal override void F2(ref int i) { } } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (5,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // internal abstract void F2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 32), + // (10,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // internal override void F2([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 32), + // (14,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // internal override void F1([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 32)); } [Fact] @@ -13533,8 +13542,8 @@ public void F2([UnscopedRef] ref int i) { } } class C2 : I { - public void F1([UnscopedRef] ref int i) { } // 1 - public void F2(ref int i) { } // 2 + public void F1([UnscopedRef] ref int i) { } + public void F2(ref int i) { } } class C3 : I { @@ -13543,12 +13552,27 @@ void I.F2([UnscopedRef] ref object o) { } } class C4 : I { - void I.F1([UnscopedRef] ref object o) { } // 3 - void I.F2(ref object o) { } // 4 + void I.F1([UnscopedRef] ref object o) { } + void I.F2(ref object o) { } } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (5,14): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // void F2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 14), + // (10,21): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public void F2([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 21), + // (14,21): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // public void F1([UnscopedRef] ref int i) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 21), + // (20,24): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // void I.F2([UnscopedRef] ref object o) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(20, 24), + // (24,24): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // void I.F1([UnscopedRef] ref object o) { } + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(24, 24)); } [Fact] @@ -13648,7 +13672,16 @@ static void Main() } }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (3,22): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // delegate void D2([UnscopedRef] ref T t); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(3, 22), + // (10,16): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // d1 = ([UnscopedRef] ref int i2) => { }; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 16), + // (13,16): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // d2 = ([UnscopedRef] ref object o2) => { }; + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(13, 16)); } [Fact] From a74d8f2db1d6c144cd4b80ad6deb1bf096d24cce Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 29 Jul 2022 08:47:55 -0700 Subject: [PATCH 06/12] Add reference to variance issue --- src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index c7808744b172f..cddde434d8c3c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -13406,6 +13406,7 @@ class B2 : A } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2. comp.VerifyDiagnostics( // (14,28): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. // internal override void F1([UnscopedRef] out int i) { i = 0; } // 1 @@ -13510,6 +13511,7 @@ class C4 : I } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2 and 4. comp.VerifyDiagnostics( // (14,17): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member. // public void F1([UnscopedRef] out int i) { i = 0; } // 1 @@ -13634,6 +13636,7 @@ static void Main() } }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + // https://github.com/dotnet/roslyn/issues/62340: Should allow removing [UnscopedRef] rather than reporting error 2. comp.VerifyDiagnostics( // (10,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1'. // d1 = ([UnscopedRef] out int i2) => { i2 = 2; }; // 1 From 7a7a0849a2453d4b077a040682ffc69940bcf506 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 29 Jul 2022 09:36:14 -0700 Subject: [PATCH 07/12] Fix build --- .../CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 8fa57278100da..a4dab588ba9dc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1326,6 +1326,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } } +#nullable enable private bool IsValidUnscopedRefAttributeTarget() { return isNullOrValidAccessor(_getMethod) && @@ -1336,6 +1337,7 @@ static bool isNullOrValidAccessor(MethodSymbol? accessor) return accessor is null || accessor.IsValidUnscopedRefAttributeTarget(); } } +#nullable disable internal bool HasDisallowNull { From 2d2deac06057df161d215e4067a78651293e25a1 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 29 Jul 2022 10:32:53 -0700 Subject: [PATCH 08/12] Update error text --- .../CSharp/Portable/CSharpResources.resx | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 4 +-- .../Portable/xlf/CSharpResources.de.xlf | 4 +-- .../Portable/xlf/CSharpResources.es.xlf | 4 +-- .../Portable/xlf/CSharpResources.fr.xlf | 4 +-- .../Portable/xlf/CSharpResources.it.xlf | 4 +-- .../Portable/xlf/CSharpResources.ja.xlf | 4 +-- .../Portable/xlf/CSharpResources.ko.xlf | 4 +-- .../Portable/xlf/CSharpResources.pl.xlf | 4 +-- .../Portable/xlf/CSharpResources.pt-BR.xlf | 4 +-- .../Portable/xlf/CSharpResources.ru.xlf | 4 +-- .../Portable/xlf/CSharpResources.tr.xlf | 4 +-- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 4 +-- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 4 +-- .../Test/Semantic/Semantics/RefFieldTests.cs | 34 +++++++++---------- 15 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 0355eb21f2c44..29e990b1ae57b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7209,6 +7209,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 66a5c6c33592c..8828a16992cde 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 8357fe44b3861..c66cad450d4a6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 1f50c8dde7517..915e6daf63948 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index c78b20dd29fe8..84850bbf74367 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 0f1310a1bcad6..b3083e9d90cb7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index ed499cd77a0b3..b9be62f0bcbe7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 39cb7ce8815cb..a796e9322b285 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 32abdd594b9d8..4ef21ca69d027 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 88cf7d174516c..fc3b9d77f1959 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 2e9cd82f6e398..193cad5a67902 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 875329faeb5ff..39fc132a63860 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 98fa64cf125b7..41a809cf9d89b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index f9a87fc279e00..63d96f77f1e25 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1578,8 +1578,8 @@ - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. - UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index cddde434d8c3c..602273013c144 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -13193,10 +13193,10 @@ ref int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (6,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref T F3A([UnscopedRef] ref T t3) => ref t3; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 23), - // (7,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (7,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 23), // (14,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope @@ -13262,10 +13262,10 @@ ref readonly int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (6,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 32), - // (7,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (7,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 32), // (14,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope @@ -13352,10 +13352,10 @@ ref int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (17,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (17,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref T F3A([UnscopedRef] R r3) Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(17, 23), - // (21,23): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (21,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public ref T F4A([UnscopedRef] scoped R r4) Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(21, 23), // (32,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope @@ -13439,13 +13439,13 @@ internal override void F2(ref int i) { } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (5,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (5,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // internal abstract void F2([UnscopedRef] ref T t); Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 32), - // (10,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (10,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // internal override void F2([UnscopedRef] ref int i) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 32), - // (14,32): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (14,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // internal override void F1([UnscopedRef] ref int i) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 32)); } @@ -13560,19 +13560,19 @@ void I.F2(ref object o) { } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (5,14): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (5,14): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // void F2([UnscopedRef] ref T t); Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 14), - // (10,21): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (10,21): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public void F2([UnscopedRef] ref int i) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 21), - // (14,21): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (14,21): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // public void F1([UnscopedRef] ref int i) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 21), - // (20,24): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (20,24): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // void I.F2([UnscopedRef] ref object o) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(20, 24), - // (24,24): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (24,24): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // void I.F1([UnscopedRef] ref object o) { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(24, 24)); } @@ -13676,13 +13676,13 @@ static void Main() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (3,22): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (3,22): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // delegate void D2([UnscopedRef] ref T t); Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(3, 22), - // (10,16): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (10,16): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // d1 = ([UnscopedRef] ref int i2) => { }; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 16), - // (13,16): error CS9064: UnscopedRefAttribute can only be applied to parameters that are passed by reference and implicitly scoped. + // (13,16): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. // d2 = ([UnscopedRef] ref object o2) => { }; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(13, 16)); } From 5c1101ae04f18498605e13a38f127462f32971ca Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Sat, 30 Jul 2022 21:08:10 -0700 Subject: [PATCH 09/12] Add HasUnscopedRefAttribute property to MethodSymbol and PropertySymbol --- .../SynthesizedStateMachineProperty.cs | 2 + .../AnonymousType.PropertySymbol.cs | 2 + .../Portable/Symbols/ErrorMethodSymbol.cs | 2 + .../Portable/Symbols/ErrorPropertySymbol.cs | 2 + .../FunctionPointerMethodSymbol.cs | 1 + .../Symbols/Metadata/PE/PEMethodSymbol.cs | 33 ++++- .../Symbols/Metadata/PE/PEPropertySymbol.cs | 38 +++++- .../CSharp/Portable/Symbols/MethodSymbol.cs | 2 + .../CSharp/Portable/Symbols/PropertySymbol.cs | 2 + .../Symbols/ReducedExtensionMethodSymbol.cs | 2 + .../Retargeting/RetargetingMethodSymbol.cs | 14 ++ .../Symbols/SignatureOnlyMethodSymbol.cs | 2 + .../Symbols/SignatureOnlyPropertySymbol.cs | 2 + .../SourceMethodSymbolWithAttributes.cs | 2 +- .../Source/SourcePropertySymbolBase.cs | 2 +- .../Symbols/Source/ThisParameterSymbol.cs | 15 ++- .../SynthesizedEntryPointSymbol.cs | 2 + .../SynthesizedGlobalMethodSymbol.cs | 2 + .../SynthesizedInstanceMethodSymbol.cs | 2 + .../SynthesizedIntrinsicOperatorSymbol.cs | 2 + .../SynthesizedStaticConstructor.cs | 2 + .../Symbols/Wrapped/WrappedMethodSymbol.cs | 2 + .../Symbols/Wrapped/WrappedPropertySymbol.cs | 2 + .../Test/Semantic/Semantics/RefFieldTests.cs | 126 ++++++++++++++++++ .../Symbols/EEMethodSymbol.cs | 2 + .../Symbols/PlaceholderMethodSymbol.cs | 2 + 26 files changed, 256 insertions(+), 11 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs index 8ca68abb3e257..aa243c9cf0172 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs @@ -153,6 +153,8 @@ public override bool IsExtern internal override bool IsRequired => false; + internal sealed override bool HasUnscopedRefAttribute => false; + internal override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs index 5d5630d1af30d..7fa7f2c09c182 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs @@ -131,6 +131,8 @@ public override bool IsAbstract internal override bool IsRequired => false; + internal sealed override bool HasUnscopedRefAttribute => false; + internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs index c28022499e6cd..2341272e590ff 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs @@ -284,5 +284,7 @@ protected override bool HasSetsRequiredMembersImpl return false; } } + + internal sealed override bool HasUnscopedRefAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs index 536658ed92722..e11767c30a2a2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs @@ -79,6 +79,8 @@ public ErrorPropertySymbol(Symbol containingSymbol, TypeSymbol type, string name internal override bool IsRequired => false; + internal sealed override bool HasUnscopedRefAttribute => false; + internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } } public override ImmutableArray Parameters { get { return ImmutableArray.Empty; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs index 3d33ae01354b3..2054a5e8375d4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs @@ -831,5 +831,6 @@ public override bool IsVararg internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; internal sealed override bool IsNullableAnalysisEnabled() => throw ExceptionUtilities.Unreachable; protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + internal sealed override bool HasUnscopedRefAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 852bf34165db0..4da3ee989e5c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -47,7 +47,7 @@ private struct PackedFlags { // We currently pack everything into a 32-bit int with the following layout: // - // |w|v|u|t|s|r|q|p|ooo|n|m|l|k|j|i|h|g|f|e|d|c|b|aaaaa| + // |y|x|w|v|u|t|s|r|q|p|ooo|n|m|l|k|j|i|h|g|f|e|d|c|b|aaaaa| // // a = method kind. 5 bits. // b = method kind populated. 1 bit. @@ -74,7 +74,9 @@ private struct PackedFlags // u = IsUnmanagedCallersOnlyAttributePopulated. 1 bit. // v = IsSetsRequiredMembersBit. 1 bit. // w = IsSetsRequiredMembersPopulated. 1 bit. - // 4 bits remain for future purposes. + // x = IsUnscopedRef. 1 bit. + // y = IsUnscopedRefPopulated. 1 bit. + // 2 bits remain for future purposes. private const int MethodKindOffset = 0; private const int MethodKindMask = 0x1F; @@ -102,6 +104,8 @@ private struct PackedFlags private const int IsUnmanagedCallersOnlyAttributePopulatedBit = 0x1 << 26; private const int HasSetsRequiredMembersBit = 0x1 << 27; private const int HasSetsRequiredMembersPopulatedBit = 0x1 << 28; + private const int IsUnscopedRefBit = 0x1 << 29; + private const int IsUnscopedRefPopulatedBit = 0x1 << 30; private int _bits; @@ -140,6 +144,8 @@ public MethodKind MethodKind public bool IsUnmanagedCallersOnlyAttributePopulated => (_bits & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; public bool HasSetsRequiredMembers => (_bits & HasSetsRequiredMembersBit) != 0; public bool HasSetsRequiredMembersPopulated => (_bits & HasSetsRequiredMembersPopulatedBit) != 0; + public bool IsUnscopedRef => (_bits & IsUnscopedRefBit) != 0; + public bool IsUnscopedRefPopulated => (_bits & IsUnscopedRefPopulatedBit) != 0; #if DEBUG static PackedFlags() @@ -254,6 +260,14 @@ public bool InitializeSetsRequiredMembersBit(bool value) return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); } + + public bool InitializeIsUnscopedRef(bool value) + { + int bitsToSet = IsUnscopedRefPopulatedBit; + if (value) bitsToSet |= IsUnscopedRefBit; + + return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } } /// @@ -1610,5 +1624,20 @@ public override bool AreLocalsZeroed internal bool TestIsExtensionBitTrue => _packedFlags.IsExtensionMethod; internal sealed override bool IsNullableAnalysisEnabled() => throw ExceptionUtilities.Unreachable; + + internal sealed override bool HasUnscopedRefAttribute + { + get + { + if (!_packedFlags.IsUnscopedRefPopulated) + { + var moduleSymbol = _containingType.ContainingPEModule; + bool unscopedRef = moduleSymbol.Module.HasUnscopedRefAttribute(_handle); + _packedFlags.InitializeIsUnscopedRef(unscopedRef); + } + + return _packedFlags.IsUnscopedRef; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index f2f94b1228dd3..a338e6e71fcf2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -53,17 +53,20 @@ internal class PEPropertySymbol private struct PackedFlags { // Layout: - // |...........................|rr|c|n|s| + // |.........................|uu|rr|c|n|s| // // s = special name flag. 1 bit // n = runtime special name flag. 1 bit // c = call methods directly flag. 1 bit // r = Required member. 2 bits (1 bit for value + 1 completion bit). + // u = Unscoped ref. 2 bits (1 bit for value + 1 completion bit). private const int IsSpecialNameFlag = 1 << 0; private const int IsRuntimeSpecialNameFlag = 1 << 1; private const int CallMethodsDirectlyFlag = 1 << 2; private const int HasRequiredMemberAttribute = 1 << 4; private const int RequiredMemberCompletionBit = 1 << 5; + private const int HasUnscopedRefAttribute = 1 << 6; + private const int UnscopedRefCompletionBit = 1 << 7; private int _bits; @@ -92,6 +95,24 @@ public bool TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute return false; } + public void SetHasUnscopedRefAttribute(bool unscopedRef) + { + var bitsToSet = (unscopedRef ? HasUnscopedRefAttribute : 0) | UnscopedRefCompletionBit; + ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } + + public bool TryGetHasUnscopedRefAttribute(out bool hasUnscopedRefAttribute) + { + if ((_bits & UnscopedRefCompletionBit) != 0) + { + hasUnscopedRefAttribute = (_bits & HasUnscopedRefAttribute) != 0; + return true; + } + + hasUnscopedRefAttribute = false; + return false; + } + public bool IsSpecialName => (_bits & IsSpecialNameFlag) != 0; public bool IsRuntimeSpecialName => (_bits & IsRuntimeSpecialNameFlag) != 0; public bool CallMethodsDirectly => (_bits & CallMethodsDirectlyFlag) != 0; @@ -507,6 +528,21 @@ internal override bool IsRequired } } + internal sealed override bool HasUnscopedRefAttribute + { + get + { + if (!_flags.TryGetHasUnscopedRefAttribute(out bool hasUnscopedRefAttribute)) + { + var containingPEModuleSymbol = (PEModuleSymbol)this.ContainingModule; + hasUnscopedRefAttribute = containingPEModuleSymbol.Module.HasAttribute(_handle, AttributeDescription.UnscopedRefAttribute); + _flags.SetHasUnscopedRefAttribute(hasUnscopedRefAttribute); + } + + return hasUnscopedRefAttribute; + } + } + public override ImmutableArray Parameters { get { return _parameters; } diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index b710bf43f30ce..340b48866c832 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -586,6 +586,8 @@ public bool IsConditional protected abstract bool HasSetsRequiredMembersImpl { get; } + internal abstract bool HasUnscopedRefAttribute { get; } + /// /// Some method kinds do not participate in overriding/hiding (e.g. constructors). /// diff --git a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs index 245c42e1b0d21..025f377e0225e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs @@ -218,6 +218,8 @@ public abstract MethodSymbol SetMethod internal abstract bool MustCallMethodsDirectly { get; } + internal abstract bool HasUnscopedRefAttribute { get; } + /// /// Returns the overridden property, or null. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index 31b4141c1479a..9bf922555216e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -590,6 +590,8 @@ public override int GetHashCode() protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + internal sealed override bool HasUnscopedRefAttribute => false; + #nullable enable private sealed class ReducedExtensionMethodParameterSymbol : WrappedParameterSymbol diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs index cde90e9074875..39f7ebdd5567c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs @@ -255,6 +255,20 @@ public override ImmutableArray GetReturnTypeAttributes() return _lazyUnmanagedAttributeData; } + + internal override bool TryGetThisParameter(out ParameterSymbol? thisParameter) + { + if (!_underlyingMethod.TryGetThisParameter(out var underlyingParameter)) + { + thisParameter = null; + return false; + } + + thisParameter = underlyingParameter is { } + ? new ThisParameterSymbol(this) + : null; + return true; + } #nullable disable public override AssemblySymbol ContainingAssembly diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs index bb92c1a6e5afb..a13a66a23baff 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs @@ -174,6 +174,8 @@ internal override bool IsMetadataFinal protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + internal sealed override bool HasUnscopedRefAttribute => false; + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs index 0c2297b9ce522..58fc55748f0c9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs @@ -63,6 +63,8 @@ public SignatureOnlyPropertySymbol( public override string Name { get { return _name; } } + internal sealed override bool HasUnscopedRefAttribute => false; + #region Not used by PropertySignatureComparer internal override bool HasSpecialName { get { throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 7af64872b8e03..d12860d29ff66 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -611,7 +611,7 @@ public override FlowAnalysisAnnotations FlowAnalysisAnnotations private static FlowAnalysisAnnotations DecodeFlowAnalysisAttributes(MethodWellKnownAttributeData attributeData) => attributeData?.HasDoesNotReturnAttribute == true ? FlowAnalysisAnnotations.DoesNotReturn : FlowAnalysisAnnotations.None; - internal bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; + internal sealed override bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; private bool VerifyObsoleteAttributeAppliedToMethod( ref DecodeWellKnownAttributeArguments arguments, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index a4dab588ba9dc..e59aab95a78bd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1393,7 +1393,7 @@ internal ImmutableArray MemberNotNullAttributeIfExists internal ImmutableArray MemberNotNullWhenAttributeIfExists => FindAttributes(AttributeDescription.MemberNotNullWhenAttribute); - internal bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; + internal sealed override bool HasUnscopedRefAttribute => GetDecodedWellKnownAttributeData()?.HasUnscopedRefAttribute == true; private SourceAttributeData FindAttribute(AttributeDescription attributeDescription) => (SourceAttributeData)GetAttributes().First(a => a.IsTargetAttribute(this, attributeDescription)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index d76db838414ef..bd7fc894e19ab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -189,13 +189,16 @@ internal override DeclarationScope EffectiveScope static bool hasUnscopedRefAttribute(MethodSymbol? containingMethod) { - if (containingMethod is SourceMethodSymbolWithAttributes { HasUnscopedRefAttribute: true }) + if (containingMethod is { }) { - return true; - } - if (containingMethod?.AssociatedSymbol is SourcePropertySymbol { HasUnscopedRefAttribute: true }) - { - return true; + if (containingMethod.HasUnscopedRefAttribute == true) + { + return true; + } + if (containingMethod.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true }) + { + return true; + } } return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 69d0a214d5b41..b836f55e63077 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -309,6 +309,8 @@ private static BoundCall CreateParameterlessCall(CSharpSyntaxNode syntax, BoundE protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + internal sealed override bool HasUnscopedRefAttribute => false; + /// A synthesized entrypoint that forwards all calls to an async Main Method internal sealed class AsyncForwardEntryPoint : SynthesizedEntryPointSymbol { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs index 893bb85ea8ed1..9c14068b8f66e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs @@ -337,5 +337,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l internal sealed override bool IsNullableAnalysisEnabled() => false; protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + + internal sealed override bool HasUnscopedRefAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs index 880613454fab0..fc53ab75d5bd6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs @@ -78,5 +78,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l public sealed override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None; internal override bool IsNullableAnalysisEnabled() => false; + + internal sealed override bool HasUnscopedRefAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 6777f7dcc2a90..46466ac5fed98 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -425,6 +425,8 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + internal sealed override bool HasUnscopedRefAttribute => false; + public override bool Equals(Symbol obj, TypeCompareKind compareKind) { if (obj == (object)this) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs index 948bd9f64071d..36d0885c90137 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs @@ -430,5 +430,7 @@ private bool CalculateShouldEmit(ImmutableArray boundInitializ } protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + + internal sealed override bool HasUnscopedRefAttribute => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs index 06f156ca7690b..43936f534a57a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs @@ -360,5 +360,7 @@ internal override bool GenerateDebugInfo internal override bool IsInitOnly => UnderlyingMethod.IsInitOnly; protected sealed override bool HasSetsRequiredMembersImpl => UnderlyingMethod.HasSetsRequiredMembers; + + internal sealed override bool HasUnscopedRefAttribute => UnderlyingMethod.HasUnscopedRefAttribute; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs index e9f62600a2a8a..8ffb1ce4fdd59 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs @@ -163,6 +163,8 @@ public override bool IsExtern internal sealed override bool IsRequired => _underlyingProperty.IsRequired; + internal sealed override bool HasUnscopedRefAttribute => _underlyingProperty.HasUnscopedRefAttribute; + internal override ObsoleteAttributeData ObsoleteAttributeData { get diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 602273013c144..3e3c47aa56458 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -12858,6 +12858,132 @@ R this[int i] Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); } + [Theory] + [CombinatorialData] + public void UnscopedRefAttribute_SubstitutedMembers(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R1 +{ + private T _t; + public R1(T t) { _t = t; } + public ref T Get() => ref this[0]; + public ref T this[int index] => throw null; +} +public ref struct R2 +{ + private T _t; + public R2(T t) { _t = t; } + [UnscopedRef] public ref T Get() => ref this[0]; + [UnscopedRef] public ref T this[int index] => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1(bool b) + { + R1 r1 = new R1(1); + if (b) return ref r1.Get(); + return ref r1[0]; + } + static ref int F2(bool b) + { + R2 r2 = new R2(2); + if (b) return ref r2.Get(); // 1 + return ref r2[0]; // 2 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + // https://github.com/dotnet/roslyn/issues/62791: Missing errors. + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text is "r1" or "r2").ToArray(); + var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).ToArray(); + + var type = types[0]; + Assert.Equal("R1", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "scoped ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "scoped ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + + type = types[1]; + Assert.Equal("R2", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + } + + [Fact] + public void UnscopedRefAttribute_RetargetingMembers() + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public ref struct R1 +{ + private readonly T _t; + public R1(T t) { _t = t; } + public ref readonly T Get() => ref this[0]; + public ref readonly T this[int index] => ref _t; // 1 +} +public ref struct R2 +{ + private readonly T _t; + public R2(T t) { _t = t; } + [UnscopedRef] public ref readonly T Get() => ref this[0]; + [UnscopedRef] public ref readonly T this[int index] => ref _t; +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Mscorlib40); + comp.VerifyDiagnostics( + // (7,50): error CS8170: Struct members cannot return 'this' or other instance members by reference + // public ref readonly T this[int index] => ref _t; // 1 + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 50)); + + var refA = comp.ToMetadataReference(); + + var sourceB = +@"class Program +{ + static ref readonly int F1(bool b) + { + R1 r1 = new R1(1); + if (b) return ref r1.Get(); + return ref r1[0]; + } + static ref readonly int F2(bool b) + { + R2 r2 = new R2(2); + if (b) return ref r2.Get(); // 1 + return ref r2[0]; // 2 + } +}"; + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + // https://github.com/dotnet/roslyn/issues/62791: Missing errors. + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var decls = tree.GetRoot().DescendantNodes().OfType().Where(v => v.Identifier.Text is "r1" or "r2").ToArray(); + var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol().Type).ToArray(); + + var type = types[0]; + var underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; + Assert.Equal("R1", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "scoped ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "scoped ref R1 this", RefKind.Ref, DeclarationScope.RefScoped); + + type = types[1]; + underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition; + Assert.Equal("R2", type.ToTestDisplayString()); + VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2 this", RefKind.Ref, DeclarationScope.Unscoped); + } + [Fact] public void UnscopedRefAttribute_Constructor() { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index cdb6bb56e93ba..6fb4e0fbc25e5 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -434,6 +434,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal sealed override UnmanagedCallersOnlyAttributeData GetUnmanagedCallersOnlyAttributeData(bool forceComplete) => throw ExceptionUtilities.Unreachable; + internal override bool HasUnscopedRefAttribute => false; + internal ResultProperties ResultProperties { get { return _lazyResultProperties; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs index bed4b97588505..b7ba65e36fe68 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs @@ -218,6 +218,8 @@ internal override ObsoleteAttributeData ObsoleteAttributeData internal sealed override UnmanagedCallersOnlyAttributeData GetUnmanagedCallersOnlyAttributeData(bool forceComplete) => throw ExceptionUtilities.Unreachable; + internal override bool HasUnscopedRefAttribute => false; + internal override bool RequiresSecurityObject { get { return false; } From 06a3c3b8b3fcc96ba546c8b4d4dd8a027ae8a786 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Sun, 31 Jul 2022 13:53:19 -0700 Subject: [PATCH 10/12] Update test --- .../Test/Semantic/Semantics/RefFieldTests.cs | 72 +++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 3e3c47aa56458..88aa83f2cb06e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -13113,11 +13113,11 @@ public class A { public ref T F1A(ref R r1) { - throw null; + return ref r1.F; } public ref T F2A(scoped ref R r2) { - throw null; + return ref r2.F; } public ref T F3A([UnscopedRef] ref R r3) { @@ -13132,8 +13132,8 @@ public ref T F4A([UnscopedRef] scoped ref R r4) comp.VerifyEmitDiagnostics(); var refA = AsReference(comp, useCompilationReference); - var sourceB = -@"class B : A + var sourceB1 = +@"class B1 : A { ref int F1B() { @@ -13145,22 +13145,23 @@ ref int F2B() { int i = 2; var r = new R(ref i); - return ref F2A(ref r); + return ref F2A(ref r); // 2 } ref int F3B() { int i = 3; var r = new R(ref i); - return ref F3A(ref r); // 2 + return ref F3A(ref r); // 3 } ref int F4B() { int i = 4; var r = new R(ref i); - return ref F4A(ref r); // 3 + return ref F4A(ref r); // 4 } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }); + comp = CreateCompilation(sourceB1, references: new[] { refA }); + // https://github.com/dotnet/roslyn/issues/62791: Missing error // 2. comp.VerifyEmitDiagnostics( // (7,20): error CS8347: Cannot use a result of 'A.F1A(ref R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope // return ref F1A(ref r); // 1 @@ -13169,23 +13170,68 @@ ref int F4B() // return ref F1A(ref r); // 1 Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(7, 28), // (19,20): error CS8347: Cannot use a result of 'A.F3A(ref R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope - // return ref F3A(ref r); // 2 + // return ref F3A(ref r); // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref r)").WithArguments("A.F3A(ref R)", "r3").WithLocation(19, 20), // (19,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local - // return ref F3A(ref r); // 2 + // return ref F3A(ref r); // 3 Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(19, 28), // (25,20): error CS8347: Cannot use a result of 'A.F4A(ref R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope - // return ref F4A(ref r); // 3 + // return ref F4A(ref r); // 4 Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref r)").WithArguments("A.F4A(ref R)", "r4").WithLocation(25, 20), // (25,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local - // return ref F4A(ref r); // 3 + // return ref F4A(ref r); // 4 Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(25, 28)); - var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + var baseType = comp.GetMember("B1").BaseTypeNoUseSiteDiagnostics; VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R r1", RefKind.Ref, DeclarationScope.Unscoped); VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref R r2", RefKind.Ref, DeclarationScope.RefScoped); VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref R r3", RefKind.Ref, DeclarationScope.Unscoped); VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); + + var sourceB2 = +@"class B2 : A +{ + ref int F1B(ref int i) + { + var r = new R(ref i); + return ref F1A(ref r); // 1 + } + ref int F2B(ref int i) + { + var r = new R(ref i); + return ref F2A(ref r); + } + ref int F3B(ref int i) + { + var r = new R(ref i); + return ref F3A(ref r); // 2 + } + ref int F4B(ref int i) + { + var r = new R(ref i); + return ref F4A(ref r); // 3 + } +}"; + comp = CreateCompilation(sourceB2, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (6,20): error CS8347: Cannot use a result of 'A.F1A(ref R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref r)").WithArguments("A.F1A(ref R)", "r1").WithLocation(6, 20), + // (6,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F1A(ref r); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(6, 28), + // (16,20): error CS8347: Cannot use a result of 'A.F3A(ref R)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope + // return ref F3A(ref r); // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref r)").WithArguments("A.F3A(ref R)", "r3").WithLocation(16, 20), + // (16,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F3A(ref r); // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(16, 28), + // (21,20): error CS8347: Cannot use a result of 'A.F4A(ref R)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope + // return ref F4A(ref r); // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref r)").WithArguments("A.F4A(ref R)", "r4").WithLocation(21, 20), + // (21,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local + // return ref F4A(ref r); // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(21, 28)); } [Fact] From df68917611b33f0aa585dec37290c2b81c0f282f Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 2 Aug 2022 11:56:41 -0700 Subject: [PATCH 11/12] Respond to feedback --- .../CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index a338e6e71fcf2..14224e42c3994 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -535,7 +535,7 @@ internal sealed override bool HasUnscopedRefAttribute if (!_flags.TryGetHasUnscopedRefAttribute(out bool hasUnscopedRefAttribute)) { var containingPEModuleSymbol = (PEModuleSymbol)this.ContainingModule; - hasUnscopedRefAttribute = containingPEModuleSymbol.Module.HasAttribute(_handle, AttributeDescription.UnscopedRefAttribute); + hasUnscopedRefAttribute = containingPEModuleSymbol.Module.HasUnscopedRefAttribute(_handle); _flags.SetHasUnscopedRefAttribute(hasUnscopedRefAttribute); } From 28081a165e27b810189cd2623870d507d6039885 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 2 Aug 2022 14:15:13 -0700 Subject: [PATCH 12/12] Combine errors --- .../CSharp/Portable/CSharpResources.resx | 7 +- .../CSharp/Portable/Errors/ErrorCode.cs | 3 +- .../CSharp/Portable/Errors/ErrorFacts.cs | 3 +- .../Source/SourceComplexParameterSymbol.cs | 2 +- .../SourceMethodSymbolWithAttributes.cs | 2 +- .../Source/SourcePropertySymbolBase.cs | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 11 +- .../Portable/xlf/CSharpResources.de.xlf | 11 +- .../Portable/xlf/CSharpResources.es.xlf | 11 +- .../Portable/xlf/CSharpResources.fr.xlf | 11 +- .../Portable/xlf/CSharpResources.it.xlf | 11 +- .../Portable/xlf/CSharpResources.ja.xlf | 11 +- .../Portable/xlf/CSharpResources.ko.xlf | 11 +- .../Portable/xlf/CSharpResources.pl.xlf | 11 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 11 +- .../Portable/xlf/CSharpResources.ru.xlf | 11 +- .../Portable/xlf/CSharpResources.tr.xlf | 11 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 11 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 11 +- .../Test/Semantic/Semantics/RefFieldTests.cs | 104 +++++++++--------- 20 files changed, 98 insertions(+), 168 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 29e990b1ae57b..5f47ca4a90620 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7205,10 +7205,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Types and aliases cannot be named 'scoped'. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 5400bca99718b..40490006d108a 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2111,8 +2111,7 @@ internal enum ErrorCode ERR_CannotMatchOnINumberBase = 9060, ERR_MisplacedScoped = 9061, ERR_ScopedTypeNameDisallowed = 9062, - ERR_UnscopedRefAttributeUnsupportedMember = 9063, - ERR_UnscopedRefAttributeUnsupportedParameter = 9064, + ERR_UnscopedRefAttributeUnsupportedTarget = 9063, #endregion diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index d2373225dc44d..89991a52a8e1d 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2212,8 +2212,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_CannotMatchOnINumberBase: case ErrorCode.ERR_MisplacedScoped: case ErrorCode.ERR_ScopedTypeNameDisallowed: - case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember: - case ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter: + case ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index b826b27741b6d..ca6bf2072e013 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -819,7 +819,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut { if (!this.IsValidUnscopedRefAttributeTarget()) { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index d12860d29ff66..b22950a592363 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -578,7 +578,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); } } else diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index e59aab95a78bd..4a6db766bde97 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1321,7 +1321,7 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut } else { - diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, arguments.AttributeSyntaxOpt.Location); + diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location); } } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 8828a16992cde..12d27a02d0d82 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1572,14 +1572,9 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index c66cad450d4a6..2aaf52461f390 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1572,14 +1572,9 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 915e6daf63948..3ff870d217ce2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1572,14 +1572,9 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 84850bbf74367..bc9b8cf0d6c55 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1572,14 +1572,9 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index b3083e9d90cb7..6ad538021cba8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1572,14 +1572,9 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index b9be62f0bcbe7..c5c07e059409b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1572,14 +1572,9 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index a796e9322b285..746e1aa85b7c9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1572,14 +1572,9 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 4ef21ca69d027..dfac99057d2a9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1572,14 +1572,9 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index fc3b9d77f1959..c273dca4f9b64 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1572,14 +1572,9 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 193cad5a67902..8c3444d5d0283 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1572,14 +1572,9 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 39fc132a63860..962a354d8cbe5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1572,14 +1572,9 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 41a809cf9d89b..0828401b045c7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1572,14 +1572,9 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 63d96f77f1e25..922e54b5c06fb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1572,14 +1572,9 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. - - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. - - - - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. - UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. + UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index 88aa83f2cb06e..c982a430e8886 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -12751,12 +12751,12 @@ object P6 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] object P3 { get; init; } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(6, 6), - // (15,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6), + // (15,10): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] init; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(15, 10)); } [Theory] @@ -12850,9 +12850,9 @@ R this[int i] // (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 1 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), - // (19,10): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // (19,10): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(19, 10), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(19, 10), // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); @@ -13013,9 +13013,9 @@ struct B // (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // r.F = ref this; // 1 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9), - // (15,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // (15,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(15, 6), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(15, 6), // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // r.F = ref this; // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9)); @@ -13034,15 +13034,15 @@ [UnscopedRef] static S() { } // 1 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] static S() { } // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(4, 6), - // (5,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), + // (5,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] static object F() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(5, 6), - // (6,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 6), + // (6,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] static object P => null; // 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(6, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 6)); } [Fact] @@ -13064,12 +13064,12 @@ record struct S }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + // (4,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] object F1() => null; // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(4, 6), - // (8,6): error CS9063: UnscopedRefAttribute can only be applied to instance methods and properties on struct types, not including constructors or 'init' accessors. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 6), + // (8,6): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // [UnscopedRef] object F2() => null; // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMember, "UnscopedRef").WithLocation(8, 6)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 6)); } [WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")] @@ -13365,12 +13365,12 @@ ref int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (6,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref T F3A([UnscopedRef] ref T t3) => ref t3; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 23), - // (7,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 23), + // (7,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 23), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(7, 23), // (14,20): error CS8347: Cannot use a result of 'A.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope // return ref F1A(ref i); // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A.F1A(ref int)", "t1").WithLocation(14, 20), @@ -13434,12 +13434,12 @@ ref readonly int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (6,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref readonly T F3A([UnscopedRef] in T t3) => ref t3; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(6, 32), - // (7,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(6, 32), + // (7,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(7, 32), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(7, 32), // (14,20): error CS8347: Cannot use a result of 'A.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope // return ref F1A(in i); // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A.F1A(in int)", "t1").WithLocation(14, 20), @@ -13524,12 +13524,12 @@ ref int F4B() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (17,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (17,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref T F3A([UnscopedRef] R r3) - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(17, 23), - // (21,23): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(17, 23), + // (21,23): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public ref T F4A([UnscopedRef] scoped R r4) - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(21, 23), + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(21, 23), // (32,20): error CS8347: Cannot use a result of 'A.F1A(R)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope // return ref F1A(r); // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A.F1A(R)", "r1").WithLocation(32, 20), @@ -13611,15 +13611,15 @@ internal override void F2(ref int i) { } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (5,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (5,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // internal abstract void F2([UnscopedRef] ref T t); - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 32), - // (10,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 32), + // (10,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // internal override void F2([UnscopedRef] ref int i) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 32), - // (14,32): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 32), + // (14,32): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // internal override void F1([UnscopedRef] ref int i) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 32)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 32)); } [Fact] @@ -13732,21 +13732,21 @@ void I.F2(ref object o) { } "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (5,14): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (5,14): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // void F2([UnscopedRef] ref T t); - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(5, 14), - // (10,21): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 14), + // (10,21): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public void F2([UnscopedRef] ref int i) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 21), - // (14,21): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 21), + // (14,21): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // public void F1([UnscopedRef] ref int i) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(14, 21), - // (20,24): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 21), + // (20,24): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // void I.F2([UnscopedRef] ref object o) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(20, 24), - // (24,24): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(20, 24), + // (24,24): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // void I.F1([UnscopedRef] ref object o) { } - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(24, 24)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(24, 24)); } [Fact] @@ -13848,15 +13848,15 @@ static void Main() }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (3,22): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + // (3,22): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // delegate void D2([UnscopedRef] ref T t); - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(3, 22), - // (10,16): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(3, 22), + // (10,16): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // d1 = ([UnscopedRef] ref int i2) => { }; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(10, 16), - // (13,16): error CS9064: UnscopedRefAttribute can only be applied to 'out' parameters and to 'ref' parameters that refer to 'ref struct' types. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 16), + // (13,16): error CS9063: UnscopedRefAttribute can only be applied to 'out' parameters, 'ref' parameters that refer to 'ref struct' types, and instance methods and properties on 'struct' types other than constructors and 'init' accessors. // d2 = ([UnscopedRef] ref object o2) => { }; - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedParameter, "UnscopedRef").WithLocation(13, 16)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(13, 16)); } [Fact]