From 939ea7262c3d5104f39ad6616af782ad53247635 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 29 Jul 2022 21:47:49 -0700 Subject: [PATCH] Disallow [UnscopedRef] on explicitly scoped parameter --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../CSharp/Portable/Errors/ErrorFacts.cs | 1 + .../Symbols/Metadata/PE/PEParameterSymbol.cs | 4 + .../Portable/Symbols/ParameterSymbol.cs | 5 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 5 - .../Symbols/Source/ParameterHelpers.cs | 4 - .../Source/SourceComplexParameterSymbol.cs | 7 +- .../Source/SourceSimpleParameterSymbol.cs | 13 +- .../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 | 240 +++++++++++++++--- 23 files changed, 292 insertions(+), 56 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3af8b3b440c0c..d8bbb6c75a8ee 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7211,4 +7211,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Target runtime doesn't support ref fields. + + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 8d5f54c049765..130055b355f4b 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2113,6 +2113,7 @@ internal enum ErrorCode ERR_ScopedTypeNameDisallowed = 9062, ERR_UnscopedRefAttributeUnsupportedTarget = 9063, ERR_RuntimeDoesNotSupportRefFields = 9064, + ERR_UnscopedScoped = 9066, #endregion diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 0dd4cea8d679b..a736e3957f8b4 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2214,6 +2214,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_ScopedTypeNameDisallowed: case ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget: case ErrorCode.ERR_RuntimeDoesNotSupportRefFields: + case ErrorCode.ERR_UnscopedScoped: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index ccda345181abd..ce1a08c7aa53d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -295,6 +295,10 @@ private PEParameterSymbol( if (_moduleSymbol.Module.HasUnscopedRefAttribute(_handle)) { + if (_moduleSymbol.Module.HasScopedRefAttribute(_handle)) + { + isBad = true; + } scope = DeclarationScope.Unscoped; } else if (refKind == RefKind.Out) diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index 4bb025069b9e3..130f32e635ef8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -416,13 +416,12 @@ internal sealed override ObsoleteAttributeData? ObsoleteAttributeData internal abstract bool HasInterpolatedStringHandlerArgumentError { get; } /// - /// The declared scope. From source, this is from the scope keyword - /// and any implicit scope, ignoring any UnscopedRefAttribute. + /// The declared scope. From source, this is from the scope keyword only. /// internal abstract DeclarationScope DeclaredScope { get; } /// - /// The effective scope. This is from the declared scope and any + /// The effective scope. This is from the declared scope, implicit scope and any /// UnscopedRefAttribute. /// internal abstract DeclarationScope EffectiveScope { get; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 5cbab0bf56f21..06617e5545428 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -355,11 +355,6 @@ private ImmutableArray MakeParameters( scope = DeclarationScope.Unscoped; } - if (refKind == RefKind.Out && scope == DeclarationScope.Unscoped) - { - scope = DeclarationScope.RefScoped; - } - var attributeLists = unboundLambda.ParameterAttributes(p); var name = unboundLambda.ParameterName(p); var location = unboundLambda.ParameterLocation(p); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 32cf7efe09d89..7b927d994a95c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -145,10 +145,6 @@ private static ImmutableArray MakeParameters DeclaredScope; + internal override DeclarationScope EffectiveScope + { + get + { + if (RefKind == RefKind.Out && DeclaredScope == DeclarationScope.Unscoped) + { + return DeclarationScope.RefScoped; + } + + return DeclaredScope; + } + } } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 4b10b6adff435..ca661e742e43b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 60708c1b525b1..549598aa726c8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 81890a02c038a..47d8037af3a6c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 40467cea5ae52..8f7a445489b76 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 b3cd5b7fbc8b4..2660958f8efc5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 76708eecf5a05..1f0a8de9334ab 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 95f8717f48446..95550005ed20a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 484df970aad97..6f6ea1c917ad5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 3b3ef126eb32b..3c92a91f10477 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 c6b90f3d74643..88970602a674e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 be1d4fc1e43cd..077cc4a3c0b1f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 0ae73f3306964..3aed208cf2fb4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 c1608c075a6cc..a3cc3f3ec2a7b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1582,6 +1582,11 @@ 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 cannot be applied to parameters that have a 'scoped' modifier. + UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + + '{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 00c213b5d3aa5..3a52cd4601032 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -13166,7 +13166,7 @@ static ref R ReturnRefStructRef(bool b, ref R x, [UnscopedRef] ref R y) } [CombinatorialData] - [Theory] + [Theory, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")] public void UnscopedRefAttribute_RefRefStructParameter_02(bool useCompilationReference) { var sourceA = @@ -13190,10 +13190,6 @@ 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 }, runtimeFeature: RuntimeFlag.ByRefFields); comp.VerifyEmitDiagnostics(); @@ -13220,12 +13216,6 @@ ref int F3B() var r = new R(ref i); return ref F3A(ref r); // 3 } - ref int F4B() - { - int i = 4; - var r = new R(ref i); - return ref F4A(ref r); // 4 - } }"; comp = CreateCompilation(sourceB1, references: new[] { refA }); // https://github.com/dotnet/roslyn/issues/62791: Missing error // 2. @@ -13241,19 +13231,12 @@ ref int F4B() 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); // 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); // 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); // 4 - Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(25, 28)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(19, 28)); 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 @@ -13273,11 +13256,6 @@ 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( @@ -13292,13 +13270,202 @@ ref int F4B(ref int i) 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)); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(16, 28)); + } + + [Fact] + public void UnscopedScoped() + { + 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; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped); + var dump = verifier.Dump(); + var refA = AsReference(comp, true); + + var sourceB = +@"class B : A +{ + ref int F1B() + { + int i = 1; + var r = new R(ref i); + return ref F1A(ref r); // 1 + } + ref int F2B() + { + int i = 2; + var r = new R(ref i); + return ref F2A(ref r); + } + ref int F3B() + { + int i = 3; + var r = new R(ref i); + return ref F3A(ref r); // 2 + } +}"; + 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)); + + 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); + } + + [Fact, WorkItem(63057, "https://github.com/dotnet/roslyn/issues/63057")] + public void UnscopedScoped_Source() + { + 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 F4A([UnscopedRef] scoped ref R r4) // 1 + { + return ref r4.F; + } + public ref T M([UnscopedRef] scoped out T t4) // 2 + { + t4 = default; + return ref t4; + } + public ref T M2([UnscopedRef] scoped in R t4) // 3 + { + throw null; + } +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields); + comp.VerifyEmitDiagnostics( + // (9,23): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public ref T F4A([UnscopedRef] scoped ref R r4) // 1 + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(9, 23), + // (13,21): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. + // public ref T M([UnscopedRef] scoped out T t4) // 2 + Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(13, 21), + // (18,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. + // public ref T M2([UnscopedRef] scoped in R t4) // 3 + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(18, 22) + ); + + var type = comp.GetMember("A"); + VerifyParameterSymbol(type.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("M").Parameters[0], "out T t4", RefKind.Out, DeclarationScope.Unscoped); + VerifyParameterSymbol(type.GetMethod("M2").Parameters[0], "in R t4", RefKind.In, DeclarationScope.Unscoped); + } + + [Fact, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")] + public void UnscopedScoped_Metadata() + { + var ilSource = """ +.class public sequential ansi sealed beforefieldinit R`1 + extends [mscorlib]System.ValueType +{ + .method public hidebysig specialname rtspecialname instance void .ctor ( !T& t ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class public auto ansi beforefieldinit A`1 + extends [mscorlib]System.Object +{ + // [UnscopedRef] scoped parameter + .method public hidebysig instance !T& F4A ( valuetype R`1& r4 ) cil managed + { + .param [1] + .custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 ) + IL_0000: ldnull + IL_0001: throw + } + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.ScopedRefAttribute + extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} + +.class public auto ansi sealed beforefieldinit System.Diagnostics.CodeAnalysis.UnscopedRefAttribute + extends [mscorlib]System.Attribute +{ + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } +} +"""; + var refA = CompileIL(ilSource); + + var sourceB = +@"class B : A +{ + ref int F4B() + { + int i = 4; + var r = new R(ref i); + return ref F4A(ref r); // 1 + } +}"; + var comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (7,20): error CS0570: 'A.F4A(ref R)' is not supported by the language + // return ref F4A(ref r); // 1 + Diagnostic(ErrorCode.ERR_BindToBogus, "F4A").WithArguments("A.F4A(ref R)").WithLocation(7, 20)); + + var baseType = comp.GetMember("B").BaseTypeNoUseSiteDiagnostics; + VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R r4", RefKind.Ref, DeclarationScope.Unscoped); } [Fact] @@ -13350,11 +13517,6 @@ 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(); @@ -13378,11 +13540,6 @@ 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. @@ -13392,7 +13549,6 @@ ref int F4B() 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); } [Fact]