From badd0a9c7d88a060259a4ceb2611f4fc50e43c73 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 16 Apr 2024 12:48:22 +0200 Subject: [PATCH 01/21] Allow unsafe blocks in iterators --- .../Portable/Binder/Binder.ValueChecks.cs | 24 +- .../Portable/Binder/Binder_Statements.cs | 8 +- .../CSharp/Portable/Binder/Binder_Unsafe.cs | 6 +- .../Portable/Binder/ExecutableCodeBinder.cs | 2 +- .../CSharp/Portable/Binder/InMethodBinder.cs | 18 +- .../CSharp/Portable/CSharpResources.resx | 9 +- .../CSharp/Portable/Errors/ErrorCode.cs | 4 +- .../CSharp/Portable/Errors/ErrorFacts.cs | 3 +- .../Portable/xlf/CSharpResources.cs.xlf | 15 +- .../Portable/xlf/CSharpResources.de.xlf | 15 +- .../Portable/xlf/CSharpResources.es.xlf | 15 +- .../Portable/xlf/CSharpResources.fr.xlf | 15 +- .../Portable/xlf/CSharpResources.it.xlf | 15 +- .../Portable/xlf/CSharpResources.ja.xlf | 15 +- .../Portable/xlf/CSharpResources.ko.xlf | 15 +- .../Portable/xlf/CSharpResources.pl.xlf | 15 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 15 +- .../Portable/xlf/CSharpResources.ru.xlf | 15 +- .../Portable/xlf/CSharpResources.tr.xlf | 15 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 15 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 15 +- .../Test/Emit2/Emit/NumericIntPtrTests.cs | 43 +- .../Semantic/Semantics/LocalFunctionTests.cs | 47 +- .../Semantic/Semantics/NativeIntegerTests.cs | 29 +- .../Semantic/Semantics/SemanticErrorTests.cs | 43 +- .../Test/Semantic/Semantics/UnsafeTests.cs | 1199 ++++++++++++++++- 26 files changed, 1468 insertions(+), 162 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 1275fa01322ef..918887857b42b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -872,12 +872,24 @@ private static bool CheckNotNamespaceOrType(BoundExpression expr, BindingDiagnos } } - private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) + private void CheckAddressOfInAsyncOrIteratorMethod(SyntaxNode node, BindValueKind valueKind, BindingDiagnosticBag diagnostics) { - if (valueKind == BindValueKind.AddressOf && this.IsInAsyncMethod()) + if (valueKind == BindValueKind.AddressOf) { - Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); + if (this.IsInAsyncMethod()) + { + Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); + } + else if (this.IsDirectlyInIterator && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) + { + Error(diagnostics, ErrorCode.ERR_AddressOfInIterator, node); + } } + } + + private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) + { + CheckAddressOfInAsyncOrIteratorMethod(node, valueKind, diagnostics); // Local constants are never variables. Local variables are sometimes // not to be treated as variables, if they are fixed, declared in a using, @@ -968,10 +980,8 @@ internal partial class Binder private bool CheckParameterValueKind(SyntaxNode node, BoundParameter parameter, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { Debug.Assert(!RequiresAssignableVariable(BindValueKind.AddressOf)); - if (valueKind == BindValueKind.AddressOf && this.IsInAsyncMethod()) - { - Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); - } + + CheckAddressOfInAsyncOrIteratorMethod(node, valueKind, diagnostics); ParameterSymbol parameterSymbol = parameter.ParameterSymbol; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index faeeb28982488..d65ff54ae46fe 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -176,9 +176,7 @@ private BoundStatement BindUnsafeStatement(UnsafeStatementSyntax node, BindingDi } else if (this.IsIndirectlyInIterator) // called *after* we know the binder map has been created. { - // Spec 8.2: "An iterator block always defines a safe context, even when its declaration - // is nested in an unsafe context." - Error(diagnostics, ErrorCode.ERR_IllegalInnerUnsafe, node.UnsafeKeyword); + CheckFeatureAvailability(node.UnsafeKeyword, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } return BindEmbeddedBlock(node.Block, diagnostics); @@ -268,6 +266,10 @@ private BoundStatement BindYieldReturnStatement(YieldStatementSyntax node, Bindi { Error(diagnostics, ErrorCode.ERR_YieldNotAllowedInScript, node.YieldKeyword); } + else if (InUnsafeRegion && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) + { + Error(diagnostics, ErrorCode.ERR_BadYieldInUnsafe, node.YieldKeyword); + } // NOTE: Error conditions should be checked above this point; only warning conditions below. else if (this.Flags.Includes(BinderFlags.InLockBody)) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs index ec8cd5d3885b7..a71d91573820e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs @@ -56,11 +56,9 @@ private CSDiagnosticInfo GetUnsafeDiagnosticInfo(TypeSymbol sizeOfTypeOpt) { return null; } - else if (this.IsIndirectlyInIterator) + else if (this.IsIndirectlyInIterator && MessageID.IDS_FeatureRefUnsafeInIteratorAsync.GetFeatureAvailabilityDiagnosticInfo(Compilation) is { } unsafeInIteratorDiagnosticInfo) { - // Spec 8.2: "An iterator block always defines a safe context, even when its declaration - // is nested in an unsafe context." - return new CSDiagnosticInfo(ErrorCode.ERR_IllegalInnerUnsafe); + return unsafeInIteratorDiagnosticInfo; } else if (!this.InUnsafeRegion) { diff --git a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs index edffa7f5535d3..e08152589f822 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs @@ -129,7 +129,7 @@ public static void ValidateIteratorMethod(CSharpCompilation compilation, MethodS if (((iterator as SourceMemberMethodSymbol)?.IsUnsafe == true || (iterator as LocalFunctionSymbol)?.IsUnsafe == true) && compilation.Options.AllowUnsafe) // Don't cascade { - diagnostics.Add(ErrorCode.ERR_IllegalInnerUnsafe, errorLocation); + MessageID.IDS_FeatureRefUnsafeInIteratorAsync.CheckFeatureAvailability(diagnostics, compilation, errorLocation); } var returnType = iterator.ReturnType; diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index c2e47a7daeadd..6c8e616f92f07 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -38,13 +38,29 @@ internal sealed class InMethodBinder : LocalScopeBinder #endif public InMethodBinder(MethodSymbol owner, Binder enclosing) - : base(enclosing, enclosing.Flags & ~BinderFlags.AllClearedAtExecutableCodeBoundary) + : base(enclosing, ConstructFlags(owner, enclosing)) { Debug.Assert(!enclosing.Flags.Includes(BinderFlags.InCatchFilter)); Debug.Assert((object)owner != null); _methodSymbol = owner; } + private static BinderFlags ConstructFlags(MethodSymbol owner, Binder enclosing) + { + BinderFlags flags = enclosing.Flags & ~BinderFlags.AllClearedAtExecutableCodeBoundary; + + if (owner.IsIterator && enclosing.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) + { + // Spec §13.3.1: "An iterator block always defines a safe context, + // even when its declaration is nested in an unsafe context." + // Note that if the iterator method itself has the unsafe modifier, + // its body binder will have the UnsafeRegion flag applied by the BinderFactory. + flags &= ~BinderFlags.UnsafeRegion; + } + + return flags; + } + private static void RecordDefinition(SmallDictionary declarationMap, ImmutableArray definitions) where T : Symbol { foreach (Symbol s in definitions) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 546daa5c1d4b1..2c09d4efb99e5 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -2950,9 +2950,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Cannot use ref, out, or in parameter '{0}' inside an anonymous method, lambda expression, query expression, or local function - - Unsafe code may not appear in iterators - Cannot yield a value in the body of a catch clause @@ -7905,4 +7902,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + Cannot use 'yield return' in an 'unsafe' block + + + The '&' operator cannot be used on parameters or local variables in iterator methods. + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index b4fb86f47e14b..7f65516069734 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -792,7 +792,7 @@ internal enum ErrorCode ERR_BadYieldInTryOfCatch = 1626, ERR_EmptyYield = 1627, ERR_AnonDelegateCantUse = 1628, - ERR_IllegalInnerUnsafe = 1629, + // ERR_IllegalInnerUnsafe = 1629, //ERR_BadWatsonMode = 1630, ERR_BadYieldInCatch = 1631, ERR_BadDelegateLeave = 1632, @@ -2305,6 +2305,8 @@ internal enum ErrorCode #endregion WRN_BadYieldInLock = 9230, + ERR_BadYieldInUnsafe = 9231, + ERR_AddressOfInIterator = 9232, // Note: you will need to do the following after adding warnings: // 1) Re-generate compiler code (eng\generate-compiler-code.cmd). diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 4722401c000b1..c599c2a5bb15f 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -1278,7 +1278,6 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefLike: case ErrorCode.ERR_AnonDelegateCantUseStructPrimaryConstructorParameterInMember: case ErrorCode.ERR_AnonDelegateCantUseStructPrimaryConstructorParameterCaptured: - case ErrorCode.ERR_IllegalInnerUnsafe: case ErrorCode.ERR_BadYieldInCatch: case ErrorCode.ERR_BadDelegateLeave: case ErrorCode.WRN_IllegalPragma: @@ -2433,6 +2432,8 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_ParamsCollectionMissingConstructor: case ErrorCode.ERR_NoModifiersOnUsing: case ErrorCode.WRN_BadYieldInLock: + case ErrorCode.ERR_BadYieldInUnsafe: + case ErrorCode.ERR_AddressOfInIterator: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index fc8ee36929979..8cfc786b84b88 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -32,6 +32,11 @@ {0}: abstraktní událost nemůže používat syntaxi přístupového objektu události. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' pro skupiny metod se nedá použít ve stromech výrazů. @@ -302,6 +307,11 @@ Typ {0} není platný pro using static. Lze použít pouze třídu, strukturu, rozhraní, výčet, delegáta nebo obor názvů. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Atribut AsyncMethodBuilder je u anonymních metod bez explicitního návratového typu zakázaný. @@ -9161,11 +9171,6 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter Parametr ref, out nebo in {0} nejde použít uvnitř anonymní metody, výrazu lambda, výrazu dotazu nebo lokální funkce. - - Unsafe code may not appear in iterators - Iterátory nesmí obsahovat nezabezpečený kód. - - Cannot yield a value in the body of a catch clause V těle klauzule catch nejde použít hodnotu získanou příkazem yield. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index d91808e6fc8ff..296db899ac590 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -32,6 +32,11 @@ {0}: Das abstrakte Ereignis kann die Ereignisaccessorsyntax nicht verwenden. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees "&" für Methodengruppen kann in Ausdrucksbaumstrukturen nicht verwendet werden. @@ -302,6 +307,11 @@ Der Typ "{0}" ist für "using static" ungültig. Nur eine Klasse, Struktur, Schnittstelle, Enumeration, ein Delegat oder ein Namespace kann verwendet werden. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Das AsyncMethodBuilder-Attribut ist für anonyme Methoden ohne expliziten Rückgabetyp unzulässig. @@ -9161,11 +9171,6 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus Der ref-, out-, oder in-Parameter "{0}" kann nicht in einer anonymen Methode, einem Lambdaausdruck, einem Abfrageausdruck oder einer lokalen Funktion verwendet werden. - - Unsafe code may not appear in iterators - Unsicherer Code wird möglicherweise nicht in Iteratoren angezeigt. - - Cannot yield a value in the body of a catch clause Mit "yield" kann im Text einer catch-Klausel kein Wert zurückgegeben werden. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 519a716d29c04..97696daf3fc40 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -32,6 +32,11 @@ "{0}": un evento abstracto no puede usar la sintaxis de descriptor de acceso de eventos + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees No se puede usar "&" para los grupos de métodos en los árboles de expresión. @@ -302,6 +307,11 @@ El tipo '{0}' no es válido para 'using static'. Solo se puede usar una clase, estructura, interfaz, enumeración, delegado o espacio de nombres. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. El atributo AsyncMethodBuilder no se permite en métodos anónimos sin un tipo de valor devuelto explícito. @@ -9161,11 +9171,6 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar No se puede usar el parámetro ref, out o in "{0}" dentro de un método anónimo, una expresión lambda, una expresión de consulta o una función local - - Unsafe code may not appear in iterators - No puede aparecer código no seguro en iteradores - - Cannot yield a value in the body of a catch clause No se puede proporcionar ningún valor en el cuerpo de una cláusula catch diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index ceb81446301bf..6bcd5e346729f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -32,6 +32,11 @@ '{0}' : un événement abstrait ne peut pas utiliser une syntaxe d'accesseur d'événement + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' des groupes de méthodes ne peut pas être utilisé dans les arborescences d'expression @@ -302,6 +307,11 @@ Le type '{0}' n'est pas valide pour 'en utilisant statique'. Seuls une classe, une structure, une interface, une énumération, un délégué ou un espace de noms peuvent être utilisés. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. L'attribut AsyncMethodBuilder n'est pas autorisé pour les méthodes anonymes sans type de retour explicite. @@ -9161,11 +9171,6 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e Impossible d'utiliser le paramètre ref, out ou in '{0}' dans une méthode anonyme, une expression lambda, une expression de requête ou une fonction locale - - Unsafe code may not appear in iterators - Du code unsafe ne peut pas s'afficher dans des itérateurs - - Cannot yield a value in the body of a catch clause Impossible de générer une valeur dans le corps d'une clause catch diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index f1568d3b31829..1fdd574f15cc6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -32,6 +32,11 @@ '{0}': l'evento astratto non può usare la sintassi della funzione di accesso agli eventi + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Non è possibile usare '&' su gruppi di metodi in alberi delle espressioni @@ -302,6 +307,11 @@ '{0}' tipo non valido per 'using static'. È possibile usare solo una classe, una struttura, un'interfaccia, un'enumerazione, un delegato o uno spazio dei nomi. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. L'attributo AsyncMethodBuilder non è consentito in metodi anonimi senza un tipo restituito esplicito. @@ -9161,11 +9171,6 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi Non è possibile usare il parametro ref, out o in '{0}' all'interno di un metodo anonimo, di un'espressione lambda, di un'espressione di query o di una funzione locale - - Unsafe code may not appear in iterators - Gli iteratori non possono contenere codice unsafe - - Cannot yield a value in the body of a catch clause Impossibile produrre un valore nel corpo di una clausola catch diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index e98478c3c0f65..3ab67482f019f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -32,6 +32,11 @@ '{0}': 抽象イベントはイベント アクセサーの構文を使用できません + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees メソッド グループの '&' を式ツリーで使用することはできません @@ -302,6 +307,11 @@ '{0}' 型は 'using static' では無効です。使用できるのは、クラス、構造体、インターフェイス、列挙型、デリゲート、名前空間のみです。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. AsyncMethodBuilder 属性は、明示的な戻り値の型のない匿名メソッドでは許可されていません。 @@ -9161,11 +9171,6 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 ref、out、in パラメーター '{0}' は、匿名メソッド、ラムダ式、クエリ式、ローカル関数の内部では使用できません - - Unsafe code may not appear in iterators - アンセーフ コードは反復子には記述できません - - Cannot yield a value in the body of a catch clause catch 句の本体で値を生成することはできません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 7e87768b4bf62..af60b68bc3d07 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -32,6 +32,11 @@ '{0}': 추상 이벤트는 이벤트 접근자 구문을 사용할 수 없습니다. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 식 트리에서는 메서드 그룹에 '&'를 사용할 수 없습니다. @@ -302,6 +307,11 @@ '{0}' 유형은 '정적 사용'에 유효하지 않습니다. 클래스, 구조체, 인터페이스, 열거형, 대리자 또는 네임스페이스만 사용할 수 있습니다. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. AsyncMethodBuilder 특성은 명시적 반환 형식이 없는 익명 메서드에서 허용되지 않습니다. @@ -9161,11 +9171,6 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA 무명 메서드, 람다 식, 쿼리 식 또는 로컬 함수 안에서는 ref, out 또는 in 매개 변수 '{0}'을(를) 사용할 수 없습니다. - - Unsafe code may not appear in iterators - 반복기에는 안전하지 않은 코드를 사용할 수 없습니다. - - Cannot yield a value in the body of a catch clause catch 절 본문에서는 값을 생성할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 7dcc59fdbd7f6..c9b6f65041b02 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -32,6 +32,11 @@ „{0}”: zdarzenie abstrakcyjne nie może używać składni metody dostępu zdarzenia + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Znak „&” dla grup metod nie może być używany w drzewach wyrażeń @@ -302,6 +307,11 @@ Typ „{0}” jest nieprawidłowy dla „using static”. Można używać tylko klasy, struktury, interfejsu, wyliczenia, delegata lub przestrzeni nazw. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Atrybut AsyncMethodBuilder jest niedozwolony w metodach anonimowych bez jawnego zwracanego typu. @@ -9161,11 +9171,6 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n Nie można użyć parametru ref, out ani in „{0}” wewnątrz metody anonimowej, wyrażenia lambda, wyrażenia zapytania lub funkcji lokalnej - - Unsafe code may not appear in iterators - Niebezpieczny kod nie może występować w iteratorach. - - Cannot yield a value in the body of a catch clause Nie można użyć instrukcji yield z wartością w treści klauzuli catch. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 578dd52d42e00..2dba1c7baee45 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -32,6 +32,11 @@ '{0}': o evento abstrato não pode usar a sintaxe do acessador de eventos + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' nos grupos de métodos não pode ser usado em árvores de expressão @@ -302,6 +307,11 @@ '{0}' tipo não é válido para 'using static'. Somente uma classe, struct, interface, enumeração, delegado ou namespace podem ser usados. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. O atributo AsyncMethodBuilder não é permitido em métodos anônimos sem um tipo de retorno explícito. @@ -9161,11 +9171,6 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar Não é possível usar os parâmetro ref, out ou in '{0}' dentro de um método anônimo, de uma expressão lambda de uma expressão de consulta ou de uma função local - - Unsafe code may not appear in iterators - Código sem segurança só pode aparecer em iteradores - - Cannot yield a value in the body of a catch clause Não é possível usar a instrução yield no corpo de uma cláusula catch diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 619ac7320a17b..12a8569d53702 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -32,6 +32,11 @@ "{0}": абстрактное событие не может использовать синтаксис метода доступа к событиям. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees "&" в группах методов не может использоваться в деревьях выражений @@ -302,6 +307,11 @@ ' {0} ' недопустим для 'использования статики'. Можно использовать только класс, структуру, интерфейс, перечисление, делегат или пространство имен. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Атрибут AsyncMethodBuilder запрещен для анонимных методов без явного типа возвращаемого значения. @@ -9162,11 +9172,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Недопустимо использовать параметр "{0}" с модификаторами ref, out или in внутри анонимного метода, лямбда-выражения, выражения запроса или локальной функции - - Unsafe code may not appear in iterators - Небезопасный код не может использоваться в итераторах. - - Cannot yield a value in the body of a catch clause Нельзя использовать оператор yield в теле предложения catch. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 981f7741495aa..c2f2c01fd7e71 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -32,6 +32,11 @@ '{0}': soyut olay, olay erişeni söz dizimini kullanamaz + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Metot gruplarındaki '&', ifade ağaçlarında kullanılamaz @@ -302,6 +307,11 @@ '{0}' türü 'using static' için geçerli değil. Yalnızca bir sınıf, yapı, arabirim, sabit liste, temsilci veya ad alanı kullanılabilir. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Açık dönüş türü olmadan, anonim yöntemlerde AsyncMethodBuilder özniteliğine izin verilmez. @@ -9161,11 +9171,6 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm Anonim metot, lambda ifadesi, sorgu ifadesi veya yerel işlev içinde '{0}' ref, out veya in parametresi kullanılamaz - - Unsafe code may not appear in iterators - Güvenli olmayan kod yineleyicilerde görünmeyebilir - - Cannot yield a value in the body of a catch clause Catch yan tümcesinin gövdesinde yield ile bir değer döndürülemez diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 5aceeb57b426c..fe0e988c8bca5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -32,6 +32,11 @@ “{0}”: 抽象事件不可使用事件访问器语法 + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 不可在表达式树中使用方法组上的 "&" @@ -302,6 +307,11 @@ “{0}”类型对于 "using static" 无效。只能使用类、结构、接口、枚举、委托或命名空间。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. 没有显式返回类型的匿名方法不允许使用 AsyncMethodBuilder 属性。 @@ -9161,11 +9171,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep 不能在匿名方法、lambda 表达式、查询表达式或本地函数中使用 ref、out 或 in 参数“{0}” - - Unsafe code may not appear in iterators - 迭代器中不能出现不安全的代码 - - Cannot yield a value in the body of a catch clause 无法在 catch 子句体中生成值 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 3b36564d36e33..f2f3842ce8508 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -32,6 +32,11 @@ '{0}' 抽象事件無法使用事件存取子語法 + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 不得在運算式樹狀架構中對方法群組使用 '&' @@ -302,6 +307,11 @@ '{0}' 類型對 'using static' 無效。只能使用類別、結構、介面、列舉、委派或命名空間。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. 沒有明確傳回型別的匿名方法上不允許 AsyncMethodBuilder 屬性。 @@ -9161,11 +9171,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep 無法在匿名方法、Lambda 運算式、查詢運算式或區域函式中使用 ref、out 或 in 參數 '{0}' - - Unsafe code may not appear in iterators - Unsafe 程式碼不可出現在迭代器中 - - Cannot yield a value in the body of a catch clause 無法在 catch 子句主體中使用 yield 產生值 diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs index 4760ca1c2c254..c12ba96764e8a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs @@ -1359,20 +1359,43 @@ static IEnumerable F() yield return sizeof(System.UIntPtr); } }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + var expectedDiagnostics = new[] + { + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nint)").WithLocation(6, 22), - // (7,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(nuint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nuint)").WithLocation(7, 22), - // (8,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nuint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(System.IntPtr); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(System.IntPtr)").WithLocation(8, 22), - // (9,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(System.IntPtr)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(System.UIntPtr); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(System.UIntPtr)").WithLocation(9, 22)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(System.UIntPtr)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22), + // (7,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nuint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nuint)").WithArguments("nuint").WithLocation(7, 22), + // (8,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(System.IntPtr); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(System.IntPtr)").WithArguments("nint").WithLocation(8, 22), + // (9,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(System.UIntPtr); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(System.UIntPtr)").WithArguments("nuint").WithLocation(9, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index d135ca3ae11dd..170b7125aba08 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -2391,24 +2391,49 @@ public unsafe IEnumerable M4(int* a) // (27,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), + // (37,40): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // IEnumerable Local(int* b) { yield break; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(37, 40), + // (39,23): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Local(&x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(39, 23), + // (39,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Local(&x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Local(&x)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(39, 17), // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), - // (33,36): error CS1629: Unsafe code may not appear in iterators + // (33,36): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public unsafe IEnumerable M4(int* a) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "M4").WithLocation(33, 36), - // (37,40): error CS1629: Unsafe code may not appear in iterators - // IEnumerable Local(int* b) { yield break; } - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "int*").WithLocation(37, 40), - // (39,23): error CS1629: Unsafe code may not appear in iterators - // Local(&x); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "&x").WithLocation(39, 23), - // (39,17): error CS1629: Unsafe code may not appear in iterators - // Local(&x); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Local(&x)").WithLocation(39, 17), + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M4").WithArguments("ref and unsafe in async and iterator methods").WithLocation(33, 36), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45)); + + var expectedDiagnostics = new[] + { + // (8,37): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* a) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(8, 37), + // (17,41): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* x) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "x").WithLocation(17, 41), + // (27,37): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* a) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), + // (33,44): error CS1637: Iterators cannot have pointer type parameters + // public unsafe IEnumerable M4(int* a) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), + // (35,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return new Func(() => + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(35, 9), + // (37,45): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* b) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45) + }; + + CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularNext.WithFeature("run-nullable-analysis", "never")).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "never")).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 320f13951a7f9..07bd155f06f33 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -4369,14 +4369,31 @@ static IEnumerable F() yield return sizeof(nuint); } }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9); - comp.VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + var expectedDiagnostics = new[] + { + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nuint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nuint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nint)").WithLocation(6, 22), - // (7,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22), + // (7,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // yield return sizeof(nuint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nuint)").WithLocation(7, 22)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nuint)").WithArguments("nuint").WithLocation(7, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index e83c4cbb6776d..caaf6545e972f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -15272,35 +15272,48 @@ class C { IEnumerator IteratorMeth() { int i; - unsafe // CS1629 + unsafe { int *p = &i; yield return *p; } } - unsafe IEnumerator IteratorMeth2() { // CS1629 + unsafe IEnumerator IteratorMeth2() { yield break; } } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (7,7): error CS1629: Unsafe code may not appear in iterators - // unsafe // CS1629 - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe"), - // (9,10): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,7): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 7), + // (9,10): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int *p = &i; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "int *"), - // (9,19): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 10), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int *p = &i; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "&i"), - // (10,24): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&i").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19), + // (10,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return *p; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "p"), - // (14,29): error CS1629: Unsafe code may not appear in iterators - // unsafe IEnumerator IteratorMeth2() { // CS1629 - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "IteratorMeth2") + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 24), + // (14,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe IEnumerator IteratorMeth2() { + Diagnostic(ErrorCode.ERR_FeatureInPreview, "IteratorMeth2").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 29) ); + + var expectedDiagnostics = new[] + { + // (9,20): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &i; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "i").WithLocation(9, 20), + // (10,10): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(10, 10) + }; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 12753c86accd8..de1f2960e4b76 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -275,9 +275,20 @@ unsafe System.Collections.Generic.IEnumerator Goo() } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Goo")); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerator Goo() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Goo").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); + + var expectedDiagnostics = new[] + { + // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) + }; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -294,9 +305,13 @@ System.Collections.Generic.IEnumerator Goo() } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -313,9 +328,13 @@ System.Collections.Generic.IEnumerator Goo() } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [WorkItem(546657, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546657")] @@ -333,9 +352,1053 @@ System.Collections.Generic.IEnumerator Goo() } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.Action a = () => { unsafe { } }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 35)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_01_Local() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19)); + + var expectedDiagnostics = new[] + { + // (8,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_01_Parameter() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M(int x) + { + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), + // (8,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 14), + // (8,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 19)); + + var expectedDiagnostics = new[] + { + // (7,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(7, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_02() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write(x); + + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + unsafe + { + x = sizeof(S); + } + yield return x; + } + } + #pragma warning disable CS0169 // The field 'S.f' is never used + struct S { int f; } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), + // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(S); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + + var expectedOutput = "4"; + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_03() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + x = sizeof(nint); + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); + + var expectedDiagnostics = new[] + { + // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_04() + { + var code = """ + unsafe class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + x = sizeof(nint); + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); + + var expectedDiagnostics = new[] + { + // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreakOnly_01_Local() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19)); + + var expectedDiagnostics = new[] + { + // (8,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreakOnly_01_Parameter() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M(int x) + { + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), + // (8,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 14), + // (8,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 19)); + + var expectedDiagnostics = new[] + { + // (7,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(7, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreakOnly_02() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write("F" + x); + + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + unsafe + { + x = sizeof(S); + } + System.Console.Write("I" + x); + yield break; + } + } + #pragma warning disable CS0169 // The field 'S.f' is never used + struct S { int f; } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), + // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(S); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + + var expectedOutput = "I4"; + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreakOnly_Async() + { + var code = """ + #pragma warning disable CS1998 // async method lacks awaits + class C + { + public async System.Collections.Generic.IAsyncEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield break; + } + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9), + // (9,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 13), + // (9,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22), + // (9,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(9, 23), + // (10,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 14), + // (10,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 19)); + + var expectedDiagnostics = new[] + { + // (9,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(9, 23) + }; + + CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_Async() + { + var code = """ + await foreach (var x in new C().M()) System.Console.Write(x); + + class C + { + public async System.Collections.Generic.IAsyncEnumerable M() + { + int x = 1; + await System.Threading.Tasks.Task.Yield(); + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (9,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 9), + // (11,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 13), + // (11,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 22), + // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), + // (12,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 14), + // (12,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 19)); + + var expectedOutput = "1"; + var expectedDiagnostics = new[] + { + // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23) + }; + var comp = CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreak() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + unsafe + { + int *p = &x; + if (*p == 3) yield break; + } + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19), + // (12,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 9), + // (14,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 13), + // (14,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 22), + // (15,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 14), + // (15,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 19), + // (18,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 9), + // (20,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(20, 13), + // (20,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(20, 22), + // (21,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // if (*p == 3) yield break; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(21, 18)); + + var expectedDiagnostics = new[] + { + // (8,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23), + // (14,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(14, 23), + // (20,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(20, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + // Should behave equivalently to Iterator_UnsafeBlock_YieldBreak. + [Fact] + public void AwaitBetweenUnsafeBlocks() + { + var code = """ + using System; + using System.Threading.Tasks; + + await new C().M(); + + class C + { + async Task Report(int x) + { + Console.Write(x); + await Task.Yield(); + } + public async Task M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + await Report(x); + unsafe + { + int *p = &x; + *p = *p + 1; + } + await Report(x); + unsafe + { + int *p = &x; + if (*p == 3) return; + } + await Report(x); + } + } + """; + var expectedDiagnostics = new[] + { + // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), + // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23), + // (30,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(30, 23) + }; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreak_Async() + { + var code = """ + await foreach (var x in new C().M()) System.Console.Write(x); + + class C + { + public async System.Collections.Generic.IAsyncEnumerable M() + { + int x = 1; + await System.Threading.Tasks.Task.Yield(); + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + await System.Threading.Tasks.Task.Yield(); + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + unsafe + { + int *p = &x; + if (*p == 3) yield break; + } + yield return x; + } + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (9,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 9), + // (11,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 13), + // (11,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 22), + // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), + // (12,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 14), + // (12,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 19), + // (16,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 9), + // (18,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 13), + // (18,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 22), + // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), + // (19,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 14), + // (19,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 19), + // (22,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(22, 9), + // (24,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(24, 13), + // (24,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(24, 22), + // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23), + // (25,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // if (*p == 3) yield break; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(25, 18)); + + var expectedOutput = "110"; + var expectedDiagnostics = new[] + { + // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), + // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), + // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23) + }; + var comp = CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeMethod_01() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write("E" + x); + + class C + { + public unsafe System.Collections.Generic.IEnumerable M() + { + System.Console.Write("I"); + yield break; + #pragma warning disable CS0162 // Unreachable code detected + System.Console.Write("B"); + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe System.Collections.Generic.IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63)); + + var expectedOutput = "I"; + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeMethod_02() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write("E" + x); + + class C + { + public unsafe System.Collections.Generic.IEnumerable M() + { + int x = 1; + int *p = &x; + *p = *p + 1; + System.Console.Write("I" + x); + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe System.Collections.Generic.IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63), + // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), + // (8,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 18), + // (9,10): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 10), + // (9,15): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 15)); + + var expectedDiagnostics = new[] + { + // (8,19): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 19) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeMethod_03() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write("E" + x); + + class C + { + public unsafe System.Collections.Generic.IEnumerable M() + { + int x = sizeof(S); + System.Console.Write("I" + x); + yield break; + } + } + #pragma warning disable CS0169 // The field 'S.f' is never used + struct S { int f; } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe System.Collections.Generic.IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63), + // (7,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int x = sizeof(S); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 17)); + + var expectedOutput = "I4"; + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeMethod_04() + { + var code = """ + class C + { + public unsafe System.Collections.Generic.IEnumerable M() + { + int x = sizeof(S); + System.Console.Write("I" + x); + yield return x; + } + } + #pragma warning disable CS0169 // The field 'S.f' is never used + struct S { int f; } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe System.Collections.Generic.IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), + // (5,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int x = sizeof(S); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); + + var expectedDiagnostics = new[] + { + // (7,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return x; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_01() + { + var code = """ + using System.Collections.Generic; + using System.Threading.Tasks; + unsafe class C + { + IEnumerable M() + { + yield return 1; + var lam = async () => await Task.Yield(); + async void local() { await Task.Yield(); } + local(); + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,31): error CS4004: Cannot await in an unsafe context + // var lam = async () => await Task.Yield(); + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(8, 31), + // (9,30): error CS4004: Cannot await in an unsafe context + // async void local() { await Task.Yield(); } + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(9, 30)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_02() + { + var code = """ + using System.Collections.Generic; + unsafe class C + { + IEnumerable M() + { + int* p = null; + yield break; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + var expectedDiagnostics = new[] + { + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_03() + { + var code = """ + using System.Collections.Generic; + class C + { + IEnumerable M() + { + int* p = null; + yield break; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + var expectedDiagnostics = new[] + { + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_04() + { + var code = """ + using System.Collections.Generic; + class C + { + IEnumerable M() + { + int* p = null; + yield return 1; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + var expectedDiagnostics = new[] + { + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_05() + { + var code = """ + using System.Collections.Generic; + unsafe class C + { + IEnumerable M() + { + int* p = null; + yield return 1; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + var expectedDiagnostics = new[] + { + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_06() + { + var code = """ + using System.Collections.Generic; + unsafe class C + { + unsafe IEnumerable M() + { + int* p = null; + yield return 1; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 29), + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + var expectedDiagnostics = new[] + { + // (7,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_07() + { + var code = """ + using System.Collections.Generic; + unsafe class C + { + unsafe IEnumerable M() + { + int* p = null; + yield break; + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe IEnumerable M() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 29), + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -936,18 +1999,47 @@ public void UnsafeIteratorSignatures() Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p")); var withUnsafeOnMembers = string.Format(template, "", "unsafe"); - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,64): error CS1637: Iterators cannot have pointer type parameters - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p"), - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator")); //this is for putting "unsafe" on an iterator, not for the parameter type + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70), + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); //this is for putting "unsafe" on an iterator, not for the parameter type + + var expectedDiagnostics = new[] + { + // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9), + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) + }; + + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); var withUnsafeOnTypeAndMembers = string.Format(template, "unsafe", "unsafe"); - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,64): error CS1637: Iterators cannot have pointer type parameters - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p"), - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator")); //this is for putting "unsafe" on an iterator, not for the parameter type + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70), + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); //this is for putting "unsafe" on an iterator, not for the parameter type + + expectedDiagnostics = [ + // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9), + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) + ]; + + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -974,18 +2066,37 @@ public void UnsafeIteratorSignatures_PointerArray() CreateCompilation(withUnsafeOnType, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); var withUnsafeOnMembers = string.Format(template, "", "unsafe"); - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe System.Collections.Generic.IEnumerable Iterator(int*[] p) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator").WithLocation(4, 56) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); + var expectedDiagnostics = new[] + { + // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) + }; + + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + var withUnsafeOnTypeAndMembers = string.Format(template, "unsafe", "unsafe"); - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe System.Collections.Generic.IEnumerable Iterator(int*[] p) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator").WithLocation(4, 56) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); + + expectedDiagnostics = [ + // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) + ]; + + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -8156,10 +9267,20 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text).VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(S); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(S)")); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); + + var expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'S' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(S); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(S)").WithArguments("S").WithLocation(6, 22) + }; + + CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -8522,10 +9643,20 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text).VerifyDiagnostics( - // (6,17): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var p = stackalloc int[1]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "stackalloc int[1]").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17)); + + var expectedDiagnostics = new[] + { + // (6,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // var p = stackalloc int[1]; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "stackalloc int[1]")); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int[1]").WithLocation(6, 17) + }; + + CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } [Fact] From a21bde7f1d9fb865d087c01c9640ec601b41d3a5 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 18 Apr 2024 14:36:21 +0200 Subject: [PATCH 02/21] Drop duplicate long diagnostic verifications --- .../Test/Semantic/Semantics/UnsafeTests.cs | 114 ------------------ 1 file changed, 114 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index de1f2960e4b76..59d2728d1e902 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -817,50 +817,6 @@ public System.Collections.Generic.IEnumerable M() } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), - // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), - // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), - // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), - // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19), - // (12,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 9), - // (14,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 13), - // (14,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 22), - // (15,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 14), - // (15,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 19), - // (18,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 9), - // (20,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(20, 13), - // (20,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(20, 22), - // (21,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // if (*p == 3) yield break; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(21, 18)); - var expectedDiagnostics = new[] { // (8,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. @@ -971,59 +927,6 @@ public async System.Collections.Generic.IAsyncEnumerable M() } """ + AsyncStreamsTypes; - CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (9,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 9), - // (11,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 13), - // (11,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 22), - // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), - // (12,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 14), - // (12,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 19), - // (16,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 9), - // (18,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 13), - // (18,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 22), - // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), - // (19,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 14), - // (19,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 19), - // (22,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(22, 9), - // (24,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(24, 13), - // (24,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(24, 22), - // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23), - // (25,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // if (*p == 3) yield break; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(25, 18)); - var expectedOutput = "110"; var expectedDiagnostics = new[] { @@ -1090,23 +993,6 @@ public unsafe System.Collections.Generic.IEnumerable M() } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe System.Collections.Generic.IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63), - // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), - // (8,18): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 18), - // (9,10): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 10), - // (9,15): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 15)); - var expectedDiagnostics = new[] { // (8,19): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. From 47c388705f445754e7380922d4223c9b1e5ed91c Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 18 Apr 2024 14:42:21 +0200 Subject: [PATCH 03/21] Use `nint` in tests to simplify --- .../Test/Semantic/Semantics/UnsafeTests.cs | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 59d2728d1e902..bb5bc51620cc4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -467,13 +467,11 @@ public System.Collections.Generic.IEnumerable M() int x; unsafe { - x = sizeof(S); + x = sizeof(nint); } yield return x; } } - #pragma warning disable CS0169 // The field 'S.f' is never used - struct S { int f; } """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( @@ -481,10 +479,10 @@ struct S { int f; } // unsafe Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(S); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); - var expectedOutput = "4"; + var expectedOutput = IntPtr.Size.ToString(); CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -657,14 +655,12 @@ public System.Collections.Generic.IEnumerable M() int x; unsafe { - x = sizeof(S); + x = sizeof(nint); } System.Console.Write("I" + x); yield break; } } - #pragma warning disable CS0169 // The field 'S.f' is never used - struct S { int f; } """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( @@ -672,10 +668,10 @@ struct S { int f; } // unsafe Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(S); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); - var expectedOutput = "I4"; + var expectedOutput = "I" + IntPtr.Size; CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -1014,13 +1010,11 @@ class C { public unsafe System.Collections.Generic.IEnumerable M() { - int x = sizeof(S); + int x = sizeof(nint); System.Console.Write("I" + x); yield break; } } - #pragma warning disable CS0169 // The field 'S.f' is never used - struct S { int f; } """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( @@ -1028,10 +1022,10 @@ struct S { int f; } // public unsafe System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63), // (7,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int x = sizeof(S); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 17)); + // int x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 17)); - var expectedOutput = "I4"; + var expectedOutput = "I" + IntPtr.Size; CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -1044,13 +1038,11 @@ class C { public unsafe System.Collections.Generic.IEnumerable M() { - int x = sizeof(S); + int x = sizeof(nint); System.Console.Write("I" + x); yield return x; } } - #pragma warning disable CS0169 // The field 'S.f' is never used - struct S { int f; } """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( @@ -1058,8 +1050,8 @@ struct S { int f; } // public unsafe System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), // (5,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int x = sizeof(S); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); + // int x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); var expectedDiagnostics = new[] { From ef59fea3e5469215702cfb352821b1bacb12f828 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 18 Apr 2024 14:57:47 +0200 Subject: [PATCH 04/21] Add more tests --- .../Test/Semantic/Semantics/UnsafeTests.cs | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index bb5bc51620cc4..4d02fcad973c4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -454,6 +454,75 @@ public System.Collections.Generic.IEnumerable M(int x) CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void Iterator_UnsafeBlock_Field_01() + { + var code = """ + class Program + { + static int _f; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + fixed (int* p = &_f) { } + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_02() + { + var code = """ + #pragma warning disable CS0649 // field is never assigned to + unsafe class Program + { + static int* _p; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + int* p = _p; + p = &p[1]; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_03() + { + var code = """ + struct S + { + public int F; + } + class Program + { + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + S s = default; + int* p = &s.F; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (12,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int* p = &s.F; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "s.F").WithLocation(12, 23)); + } + [Fact] public void Iterator_UnsafeBlock_02() { @@ -1064,6 +1133,62 @@ public unsafe System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void Iterator_LocalFunction_01() + { + var code = """ + class Program + { + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + static void G(int x) + { + int* p = &x; + } + G(0); + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_LocalFunction_02() + { + var code = """ + class Program + { + static void F() + { + unsafe + { + static System.Collections.Generic.IEnumerable G(int x) + { + unsafe + { + int* p = &x; + } + yield return sizeof(nint); + yield break; + } + G(0); + } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (11,31): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int* p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(11, 31), + // (13,30): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 30)); + } + [Fact] public void UnsafeContext_01() { From 8fc5539e07933d62ad982dde55e9c12d709466e1 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Wed, 24 Apr 2024 15:38:40 +0200 Subject: [PATCH 05/21] Handle more iterator kinds --- .../BinderFactory.BinderFactoryVisitor.cs | 11 +- .../CSharp/Portable/Binder/Binder_Flags.cs | 23 +- .../CSharp/Portable/Binder/InMethodBinder.cs | 18 +- .../Portable/Binder/LocalBinderFactory.cs | 4 +- .../Semantic/Semantics/LocalFunctionTests.cs | 12 +- .../Test/Semantic/Semantics/UnsafeTests.cs | 854 ++++++++++++++++++ 6 files changed, 891 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 6cd5b93fc0a6f..47505ebfa9021 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -180,7 +180,8 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers); + resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers, + isIterator: usage == NodeUsage.MethodBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } @@ -339,7 +340,8 @@ private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, + isIterator: inBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } @@ -399,7 +401,7 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta Binder resultBinder; if (!binderCache.TryGetValue(key, out resultBinder)) { - resultBinder = VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = VisitCore(parent.Parent); var propertySymbol = GetPropertySymbol(parent, resultBinder); var accessor = propertySymbol.GetMethod; @@ -408,6 +410,9 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta resultBinder = new InMethodBinder(accessor, resultBinder); } + resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, + isIterator: accessor?.IsIterator == true); + binderCache.TryAdd(key, resultBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index 7374ede9d1163..cbfb2051a5c27 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -91,11 +91,26 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing); } - internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers) + internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIterator = false) { - return (this.Flags.Includes(BinderFlags.UnsafeRegion) || !modifiers.Any(SyntaxKind.UnsafeKeyword)) - ? this - : new Binder(this, this.Flags | BinderFlags.UnsafeRegion); + var insideUnsafe = this.Flags.Includes(BinderFlags.UnsafeRegion); + var hasUnsafeModifier = modifiers.Any(SyntaxKind.UnsafeKeyword); + + if (insideUnsafe == hasUnsafeModifier) + { + return this; + } + + if (insideUnsafe) + { + Debug.Assert(!hasUnsafeModifier); + return isIterator && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync) + ? new Binder(this, this.Flags & ~BinderFlags.UnsafeRegion) + : this; + } + + Debug.Assert(hasUnsafeModifier); + return new Binder(this, this.Flags | BinderFlags.UnsafeRegion); } internal Binder WithCheckedOrUncheckedRegion(bool @checked) diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index 6c8e616f92f07..c2e47a7daeadd 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -38,29 +38,13 @@ internal sealed class InMethodBinder : LocalScopeBinder #endif public InMethodBinder(MethodSymbol owner, Binder enclosing) - : base(enclosing, ConstructFlags(owner, enclosing)) + : base(enclosing, enclosing.Flags & ~BinderFlags.AllClearedAtExecutableCodeBoundary) { Debug.Assert(!enclosing.Flags.Includes(BinderFlags.InCatchFilter)); Debug.Assert((object)owner != null); _methodSymbol = owner; } - private static BinderFlags ConstructFlags(MethodSymbol owner, Binder enclosing) - { - BinderFlags flags = enclosing.Flags & ~BinderFlags.AllClearedAtExecutableCodeBoundary; - - if (owner.IsIterator && enclosing.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) - { - // Spec §13.3.1: "An iterator block always defines a safe context, - // even when its declaration is nested in an unsafe context." - // Note that if the iterator method itself has the unsafe modifier, - // its body binder will have the UnsafeRegion flag applied by the BinderFactory. - flags &= ~BinderFlags.UnsafeRegion; - } - - return flags; - } - private static void RecordDefinition(SmallDictionary declarationMap, ImmutableArray definitions) where T : Symbol { foreach (Symbol s in definitions) diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index 0695fe3f94395..37e81e2479bc4 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -416,7 +416,9 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no ? new WithMethodTypeParametersBinder(match, _enclosing) : _enclosing; - binder = binder.WithUnsafeRegionIfNecessary(node.Modifiers); + binder = binder.WithUnsafeRegionIfNecessary(node.Modifiers, + isIterator: match.IsIterator); + binder = new InMethodBinder(match, binder); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 170b7125aba08..54c2d65101c7a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -2391,6 +2391,12 @@ public unsafe IEnumerable M4(int* a) // (27,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), + // (33,44): error CS1637: Iterators cannot have pointer type parameters + // public unsafe IEnumerable M4(int* a) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), + // (33,36): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe IEnumerable M4(int* a) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M4").WithArguments("ref and unsafe in async and iterator methods").WithLocation(33, 36), // (37,40): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // IEnumerable Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(37, 40), @@ -2400,12 +2406,6 @@ public unsafe IEnumerable M4(int* a) // (39,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Local(&x); Diagnostic(ErrorCode.ERR_FeatureInPreview, "Local(&x)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(39, 17), - // (33,44): error CS1637: Iterators cannot have pointer type parameters - // public unsafe IEnumerable M4(int* a) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), - // (33,36): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe IEnumerable M4(int* a) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M4").WithArguments("ref and unsafe in async and iterator methods").WithLocation(33, 36), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 4d02fcad973c4..0bbab9dc47590 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -523,6 +523,30 @@ static System.Collections.Generic.IEnumerable F() Diagnostic(ErrorCode.ERR_AddressOfInIterator, "s.F").WithLocation(12, 23)); } + [Fact] + public void Iterator_UnsafeBlock_Field_04() + { + var code = """ + class Program + { + static int _f; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + int* p = &_f; + (*p)++; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,22): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer + // int* p = &_f; + Diagnostic(ErrorCode.ERR_FixedNeeded, "&_f").WithLocation(8, 22)); + } + [Fact] public void Iterator_UnsafeBlock_02() { @@ -745,6 +769,29 @@ public System.Collections.Generic.IEnumerable M() CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } + [Fact] + public void Iterator_UnsafeBlock_YieldBreakOnly_03() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write("F" + x); + + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + unsafe + { + x = sizeof(nint); + System.Console.Write("I" + x); + yield break; + } + } + } + """; + CompileAndVerify(code, expectedOutput: "I" + IntPtr.Size, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + [Fact] public void Iterator_UnsafeBlock_YieldBreakOnly_Async() { @@ -1011,6 +1058,74 @@ public async System.Collections.Generic.IAsyncEnumerable M() CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void Iterator_Property_01() + { + var code = """ + var c = new C(); + c.M = new[] { 42 }; + foreach (var y in c.M) System.Console.Write("Y" + y); + class C + { + public System.Collections.Generic.IEnumerable M + { + get + { + int x = 1; + unsafe + { + x = sizeof(nint); + } + yield return x; + } + set + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + System.Console.Write("X" + x); + } + } + } + """; + CompileAndVerify(code, expectedOutput: "X2Y" + IntPtr.Size, options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_Property_02() + { + var code = """ + var c = new C(); + c.M = new[] { 42 }; + foreach (var y in c.M) System.Console.Write("Y" + y); + class C + { + public unsafe System.Collections.Generic.IEnumerable M + { + get + { + int x = 1; + x = sizeof(nint); + yield break; + } + set + { + int x = 1; + int *p = &x; + *p = *p + 1; + System.Console.Write("X" + x); + } + } + } + """; + CompileAndVerify(code, expectedOutput: "X2", options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails).VerifyDiagnostics(); + } + [Fact] public void Iterator_UnsafeMethod_01() { @@ -1404,6 +1519,745 @@ unsafe IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } + [Theory, CombinatorialData] + public void UnsafeContext_Method(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeMethod ? "unsafe" : "")}} + int* + M(int* p) + { + return p; + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeMethod) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), + // (11,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 7), + // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // return p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeMethod ? "unsafe" : "")}} + System.Collections.Generic.IEnumerable + M(int* p) + { + yield return *p; + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeMethod) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,12): error CS1637: Iterators cannot have pointer type parameters + // M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), + // (13,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 9)); + } + else if (unsafeClass) + { + // Signature is unsafe (like the class), body is safe. + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,12): error CS1637: Iterators cannot have pointer type parameters + // M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), + // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (11,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 7), + // (11,12): error CS1637: Iterators cannot have pointer type parameters + // M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), + // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator(bool unsafeClass, bool unsafeOperator) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeOperator ? "unsafe" : "")}} + public static int* + operator+(C c, int* p) + { + return p; + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeOperator) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (10,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public static int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 19), + // (11,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 20), + // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // return p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Iterator(bool unsafeClass, bool unsafeOperator) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeOperator ? "unsafe" : "")}} + public static System.Collections.Generic.IEnumerable + operator+(C c, int* p) + { + yield return *p; + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeOperator) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,25): error CS1637: Iterators cannot have pointer type parameters + // operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), + // (13,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 9)); + } + else if (unsafeClass) + { + // Signature is unsafe (like the class), body is safe. + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,25): error CS1637: Iterators cannot have pointer type parameters + // operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), + // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (11,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 20), + // (11,25): error CS1637: Iterators cannot have pointer type parameters + // operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), + // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer(bool unsafeClass, bool unsafeIndexer) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeIndexer ? "unsafe" : "")}} + int* + this[int* p] + { + get => p; + set { p = value; } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeIndexer) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), + // (11,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 10), + // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // get => p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { p = value; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 15), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { p = value; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p = value").WithLocation(14, 15), + // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { p = value; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value").WithLocation(14, 19)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Iterator(bool unsafeClass, bool unsafeIndexer) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeIndexer ? "unsafe" : "")}} + System.Collections.Generic.IEnumerable + this[int* p] + { + get { yield return *p; } + set { p = null; } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeIndexer) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,15): error CS1637: Iterators cannot have pointer type parameters + // this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), + // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // get { yield return *p; } + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + } + else if (unsafeClass) + { + // Signature is unsafe (like the class), body is safe. + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (11,15): error CS1637: Iterators cannot have pointer type parameters + // this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), + // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // get { yield return *p; } + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (11,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 10), + // (11,15): error CS1637: Iterators cannot have pointer type parameters + // this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), + // (13,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // get { yield return *p; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 29), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 15), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p = null").WithLocation(14, 15)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property(bool unsafeClass, bool unsafeProperty) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeProperty ? "unsafe" : "")}} + int* + P + { + get => null; + set { value = null; } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeProperty) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { value = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value").WithLocation(14, 15), + // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { value = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value = null").WithLocation(14, 15)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property_Iterator(bool unsafeClass, bool unsafeProperty) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + [A(null)] + {{(unsafeProperty ? "unsafe" : "")}} + System.Collections.Generic.IEnumerable + P + { + get { yield return sizeof(nint); } + set { int x = sizeof(nint); } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeProperty) + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + } + else if (unsafeClass) + { + // Signature is unsafe (like the class), body is unsafe. + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + } + else + { + comp.VerifyDiagnostics( + // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), + // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), + // (13,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 28), + // (14,23): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // set { int x = sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(14, 23)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction(bool unsafeClass, bool unsafeMethod, bool unsafeBlock, bool unsafeLocalFunction) + { + var code = $$""" + #pragma warning disable CS8321 // local function is never used + + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M() + { + {{(unsafeBlock ? "unsafe" : "")}} { + [A(null)] + {{(unsafeLocalFunction ? "unsafe" : "")}} + int* + local(int* p) + { + return p; + } + } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeMethod || unsafeBlock || unsafeLocalFunction) + { + comp.VerifyDiagnostics( + // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14)); + } + else + { + comp.VerifyDiagnostics( + // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), + // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(13, 16), + // (15,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(15, 13), + // (16,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // local(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(16, 19), + // (18,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // return p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 24)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction_Iterator(bool unsafeClass, bool unsafeMethod, bool unsafeBlock, bool unsafeLocalFunction) + { + var code = $$""" + #pragma warning disable CS8321 // local function is never used + + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M() + { + {{(unsafeBlock ? "unsafe" : "")}} { + [A(null)] + {{(unsafeLocalFunction ? "unsafe" : "")}} + System.Collections.Generic.IEnumerable + local(int* p) + { + yield return *p; + } + } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeLocalFunction) + { + comp.VerifyDiagnostics( + // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), + // (16,24): error CS1637: Iterators cannot have pointer type parameters + // local(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), + // (18,17): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(18, 17)); + } + else if (unsafeClass || unsafeMethod || unsafeBlock) + { + // Signature is unsafe (like the containing scope), body is safe. + comp.VerifyDiagnostics( + // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), + // (16,24): error CS1637: Iterators cannot have pointer type parameters + // local(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), + // (18,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 31)); + } + else + { + comp.VerifyDiagnostics( + // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), + // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(13, 16), + // (16,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // local(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(16, 19), + // (16,24): error CS1637: Iterators cannot have pointer type parameters + // local(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), + // (18,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 31)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Lambda(bool unsafeClass, bool unsafeMethod, bool unsafeBlock) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M() + { + {{(unsafeBlock ? "unsafe" : "")}} { + var lam = + [A(null)] + int* + (int* p) + => p; + } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeMethod || unsafeBlock) + { + comp.VerifyDiagnostics( + // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14)); + } + else + { + comp.VerifyDiagnostics( + // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), + // (12,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(12, 16), + // (13,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 13), + // (14,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // (int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(14, 14), + // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // (int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 19), + // (15,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // => p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(15, 20)); + } + } + + [Theory, CombinatorialData] + public void UnsafeContext_Lambda_Iterator(bool unsafeClass, bool unsafeMethod, bool unsafeBlock) + { + var code = $$""" + class A : System.Attribute + { + public unsafe A(int* p) { } + } + + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M() + { + {{(unsafeBlock ? "unsafe" : "")}} { + var lam = + [A(null)] + System.Collections.Generic.IEnumerable + (int* p) => + { + yield return *p; + }; + } + } + } + """; + var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); + if (unsafeClass || unsafeMethod || unsafeBlock) + { + // Lambda cannot be an iterator, hence it always inherits `unsafe`. + comp.VerifyDiagnostics( + // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), + // (14,22): error CS1643: Not all code paths return a value in lambda expression of type '' + // (int* p) => + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "").WithLocation(14, 22), + // (16,17): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return *p; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(16, 17), + // (16,17): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(16, 17)); + } + else + { + comp.VerifyDiagnostics( + // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type + // [A(null)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), + // (12,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // [A(null)] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(12, 16), + // (14,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // (int* p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(14, 14), + // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // (int* p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 19), + // (14,22): error CS1643: Not all code paths return a value in lambda expression of type '' + // (int* p) => + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "").WithLocation(14, 22), + // (16,17): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return *p; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(16, 17), + // (16,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // yield return *p; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(16, 31)); + } + } + [Fact] public void UnsafeModifier() { From ce436917bd9844e69176e5b6a38f5327157e6a76 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 25 Apr 2024 15:11:08 +0200 Subject: [PATCH 06/21] Make unsafe affect only signature, not iterator body --- .../BinderFactory.BinderFactoryVisitor.cs | 6 +- .../CSharp/Portable/Binder/Binder_Flags.cs | 23 +- .../Portable/Binder/LocalBinderFactory.cs | 2 +- .../Semantic/Semantics/LocalFunctionTests.cs | 14 +- .../Test/Semantic/Semantics/UnsafeTests.cs | 206 ++++++++---------- 5 files changed, 110 insertions(+), 141 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 47505ebfa9021..e998f9565ffc3 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -181,7 +181,7 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl } resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers, - isIterator: usage == NodeUsage.MethodBody && method?.IsIterator == true); + isIteratorBody: usage == NodeUsage.MethodBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } @@ -341,7 +341,7 @@ private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax } resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, - isIterator: inBody && method?.IsIterator == true); + isIteratorBody: inBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } @@ -411,7 +411,7 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta } resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, - isIterator: accessor?.IsIterator == true); + isIteratorBody: accessor?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index cbfb2051a5c27..361b05b7df609 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -91,26 +91,23 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing); } - internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIterator = false) + internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) { - var insideUnsafe = this.Flags.Includes(BinderFlags.UnsafeRegion); - var hasUnsafeModifier = modifiers.Any(SyntaxKind.UnsafeKeyword); + // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context. + // In C# 12 and below, we keep the behavior that nested iterator bodies (e.g., local functions) + // inherit the safe/unsafe context from their containing scope to avoid a breaking change. + var withoutUnsafe = isIteratorBody && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync); - if (insideUnsafe == hasUnsafeModifier) + if (this.Flags.Includes(BinderFlags.UnsafeRegion)) { - return this; - } - - if (insideUnsafe) - { - Debug.Assert(!hasUnsafeModifier); - return isIterator && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync) + return withoutUnsafe ? new Binder(this, this.Flags & ~BinderFlags.UnsafeRegion) : this; } - Debug.Assert(hasUnsafeModifier); - return new Binder(this, this.Flags | BinderFlags.UnsafeRegion); + return !withoutUnsafe && modifiers.Any(SyntaxKind.UnsafeKeyword) + ? new Binder(this, this.Flags | BinderFlags.UnsafeRegion) + : this; } internal Binder WithCheckedOrUncheckedRegion(bool @checked) diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index 37e81e2479bc4..ccf79e2cf0578 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -417,7 +417,7 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no : _enclosing; binder = binder.WithUnsafeRegionIfNecessary(node.Modifiers, - isIterator: match.IsIterator); + isIteratorBody: match.IsIterator); binder = new InMethodBinder(match, binder); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 54c2d65101c7a..7e4c694e57ba1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -2424,12 +2424,18 @@ public unsafe IEnumerable M4(int* a) // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), - // (35,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return new Func(() => - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(35, 9), + // (37,40): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // IEnumerable Local(int* b) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(37, 40), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* b) { yield break; } - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45), + // (39,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // Local(&x); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "Local(&x)").WithLocation(39, 17), + // (39,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // Local(&x); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(39, 23) }; CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularNext.WithFeature("run-nullable-analysis", "never")).VerifyDiagnostics(expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 0bbab9dc47590..d684b07b556ee 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -280,15 +280,8 @@ unsafe System.Collections.Generic.IEnumerator Goo() // unsafe System.Collections.Generic.IEnumerator Goo() Diagnostic(ErrorCode.ERR_FeatureInPreview, "Goo").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); - var expectedDiagnostics = new[] - { - // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) - }; - - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -1126,6 +1119,39 @@ public unsafe System.Collections.Generic.IEnumerable M verify: Verification.Fails).VerifyDiagnostics(); } + [Theory, CombinatorialData] + public void Iterator_Indexer_01(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable this[int x] + { + get // error in C# 12: unsafe code may not appear in iterators + { + yield return 1; // error in C# 13: yield in unsafe context + } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get // error in C# 12: unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + var expectedDiagnostics = new[] + { + // (7,13): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; // error in C# 13: yield in unsafe context + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 13) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Fact] public void Iterator_UnsafeMethod_01() { @@ -1175,9 +1201,21 @@ public unsafe System.Collections.Generic.IEnumerable M() var expectedDiagnostics = new[] { + // (8,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int *p = &x; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int *").WithLocation(8, 9), + // (8,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int *p = &x; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(8, 18), // (8,19): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. // int *p = &x; - Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 19) + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 19), + // (9,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(9, 10), + // (9,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(9, 15) }; CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); @@ -1188,30 +1226,33 @@ public unsafe System.Collections.Generic.IEnumerable M() public void Iterator_UnsafeMethod_03() { var code = """ - foreach (var x in new C().M()) System.Console.Write("E" + x); - class C { public unsafe System.Collections.Generic.IEnumerable M() { int x = sizeof(nint); - System.Console.Write("I" + x); yield break; } } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public unsafe System.Collections.Generic.IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63), - // (7,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), + // (5,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 17)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); - var expectedOutput = "I" + IntPtr.Size; - CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); - CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + var expectedDiagnostics = new[] + { + // (5,17): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // int x = sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 17) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -1223,7 +1264,6 @@ class C public unsafe System.Collections.Generic.IEnumerable M() { int x = sizeof(nint); - System.Console.Write("I" + x); yield return x; } } @@ -1239,9 +1279,9 @@ public unsafe System.Collections.Generic.IEnumerable M() var expectedDiagnostics = new[] { - // (7,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return x; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 9) + // (5,17): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // int x = sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 17) }; CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); @@ -1483,9 +1523,9 @@ unsafe IEnumerable M() var expectedDiagnostics = new[] { - // (7,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 9) + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) }; CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); @@ -1515,8 +1555,15 @@ unsafe IEnumerable M() // int* p = null; Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + var expectedDiagnostics = new[] + { + // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1589,20 +1636,7 @@ public unsafe A(int* p) { } } """; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeMethod) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,12): error CS1637: Iterators cannot have pointer type parameters - // M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), - // (13,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return *p; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 9)); - } - else if (unsafeClass) + if (unsafeClass || unsafeMethod) { // Signature is unsafe (like the class), body is safe. comp.VerifyDiagnostics( @@ -1707,20 +1741,7 @@ public static System.Collections.Generic.IEnumerable } """; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeOperator) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,25): error CS1637: Iterators cannot have pointer type parameters - // operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), - // (13,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return *p; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 9)); - } - else if (unsafeClass) + if (unsafeClass || unsafeOperator) { // Signature is unsafe (like the class), body is safe. comp.VerifyDiagnostics( @@ -1836,20 +1857,7 @@ public unsafe A(int* p) { } } """; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeIndexer) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,15): error CS1637: Iterators cannot have pointer type parameters - // this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), - // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // get { yield return *p; } - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); - } - else if (unsafeClass) + if (unsafeClass || unsafeIndexer) { // Signature is unsafe (like the class), body is safe. comp.VerifyDiagnostics( @@ -1962,17 +1970,7 @@ public unsafe A(int* p) { } } """; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeProperty) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); - } - else if (unsafeClass) + if (unsafeClass || unsafeProperty) { // Signature is unsafe (like the class), body is unsafe. comp.VerifyDiagnostics( @@ -2085,20 +2083,7 @@ public unsafe A(int* p) { } } """; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeLocalFunction) - { - comp.VerifyDiagnostics( - // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), - // (16,24): error CS1637: Iterators cannot have pointer type parameters - // local(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), - // (18,17): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return *p; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(18, 17)); - } - else if (unsafeClass || unsafeMethod || unsafeBlock) + if (unsafeClass || unsafeMethod || unsafeBlock || unsafeLocalFunction) { // Signature is unsafe (like the containing scope), body is safe. comp.VerifyDiagnostics( @@ -2866,9 +2851,6 @@ public void UnsafeIteratorSignatures() var expectedDiagnostics = new[] { - // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9), // (4,70): error CS1637: Iterators cannot have pointer type parameters // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) @@ -2887,9 +2869,6 @@ public void UnsafeIteratorSignatures() Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); //this is for putting "unsafe" on an iterator, not for the parameter type expectedDiagnostics = [ - // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9), // (4,70): error CS1637: Iterators cannot have pointer type parameters // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) @@ -2929,15 +2908,8 @@ public void UnsafeIteratorSignatures_PointerArray() Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); - var expectedDiagnostics = new[] - { - // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) - }; - - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); var withUnsafeOnTypeAndMembers = string.Format(template, "unsafe", "unsafe"); CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( @@ -2946,14 +2918,8 @@ public void UnsafeIteratorSignatures_PointerArray() Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); - expectedDiagnostics = [ - // (6,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(6, 9) - ]; - - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] From c1672a8ed3774e3ee87bc41870a1e776f8277c61 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 25 Apr 2024 15:39:43 +0200 Subject: [PATCH 07/21] Fix comments --- .../CSharp/Test/Semantic/Semantics/UnsafeTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index d684b07b556ee..7a43d6dbc3c60 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -1638,7 +1638,7 @@ public unsafe A(int* p) { } var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); if (unsafeClass || unsafeMethod) { - // Signature is unsafe (like the class), body is safe. + // Signature is unsafe, body is safe. comp.VerifyDiagnostics( // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] @@ -1743,7 +1743,7 @@ public static System.Collections.Generic.IEnumerable var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); if (unsafeClass || unsafeOperator) { - // Signature is unsafe (like the class), body is safe. + // Signature is unsafe, body is safe. comp.VerifyDiagnostics( // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] @@ -1859,7 +1859,7 @@ public unsafe A(int* p) { } var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); if (unsafeClass || unsafeIndexer) { - // Signature is unsafe (like the class), body is safe. + // Signature and setter is unsafe, getter is safe. comp.VerifyDiagnostics( // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] @@ -1972,7 +1972,7 @@ public unsafe A(int* p) { } var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); if (unsafeClass || unsafeProperty) { - // Signature is unsafe (like the class), body is unsafe. + // Signature and setter is unsafe, getter is safe. comp.VerifyDiagnostics( // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] @@ -2085,7 +2085,7 @@ public unsafe A(int* p) { } var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); if (unsafeClass || unsafeMethod || unsafeBlock || unsafeLocalFunction) { - // Signature is unsafe (like the containing scope), body is safe. + // Signature is unsafe, body is safe. comp.VerifyDiagnostics( // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] From 739d04b7d8da42d7d345b76c178c730fabb56e78 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Fri, 26 Apr 2024 11:13:48 +0200 Subject: [PATCH 08/21] Rename method setting or clearing unsafe region --- .../BinderFactory.BinderFactoryVisitor.cs | 26 +++++++++---------- .../CSharp/Portable/Binder/Binder_Flags.cs | 2 +- .../Portable/Binder/LocalBinderFactory.cs | 2 +- .../Symbols/Source/LocalFunctionSymbol.cs | 2 +- .../Symbols/Source/SourcePropertySymbol.cs | 4 +-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index e998f9565ffc3..240efe35a5b3a 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -180,7 +180,7 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers, + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(methodDecl.Modifiers, isIteratorBody: usage == NodeUsage.MethodBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); } @@ -219,7 +219,7 @@ public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax } } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -246,7 +246,7 @@ public override Binder VisitDestructorDeclaration(DestructorDeclarationSyntax pa SourceMemberMethodSymbol method = GetMethodSymbol(parent, resultBinder); resultBinder = new InMethodBinder(method, resultBinder); - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -340,7 +340,7 @@ private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, isIteratorBody: inBody && method?.IsIterator == true); binderCache.TryAdd(key, resultBinder); @@ -361,24 +361,24 @@ public override Binder VisitConversionOperatorDeclaration(ConversionOperatorDecl public override Binder VisitFieldDeclaration(FieldDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitEventDeclaration(EventDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitEventFieldDeclaration(EventFieldDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitPropertyDeclaration(PropertyDeclarationSyntax parent) { if (!LookupPosition.IsInBody(_position, parent)) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } return VisitPropertyOrIndexerExpressionBody(parent); @@ -388,7 +388,7 @@ public override Binder VisitIndexerDeclaration(IndexerDeclarationSyntax parent) { if (!LookupPosition.IsInBody(_position, parent)) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } return VisitPropertyOrIndexerExpressionBody(parent); @@ -410,7 +410,7 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta resultBinder = new InMethodBinder(accessor, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers, + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, isIteratorBody: accessor?.IsIterator == true); binderCache.TryAdd(key, resultBinder); @@ -664,7 +664,7 @@ public override Binder VisitDelegateDeclaration(DelegateDeclarationSyntax parent resultBinder = new WithClassTypeParametersBinder(container, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -692,7 +692,7 @@ public override Binder VisitEnumDeclaration(EnumDeclarationSyntax parent) resultBinder = new InContainerBinder(container, outer); - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -774,7 +774,7 @@ internal Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage } } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index 361b05b7df609..130a16dab4598 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -91,7 +91,7 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing); } - internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) + internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) { // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context. // In C# 12 and below, we keep the behavior that nested iterator bodies (e.g., local functions) diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index ccf79e2cf0578..1e6ee6bfc4953 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -416,7 +416,7 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no ? new WithMethodTypeParametersBinder(match, _enclosing) : _enclosing; - binder = binder.WithUnsafeRegionIfNecessary(node.Modifiers, + binder = binder.SetOrClearUnsafeRegionIfNecessary(node.Modifiers, isIteratorBody: match.IsIterator); binder = new InMethodBinder(match, binder); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index cd3aec6946c79..d502a7080b83c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -58,7 +58,7 @@ public LocalFunctionSymbol( ScopeBinder = binder; - binder = binder.WithUnsafeRegionIfNecessary(syntax.Modifiers); + binder = binder.SetOrClearUnsafeRegionIfNecessary(syntax.Modifiers); if (syntax.TypeParameterList != null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index af93d12c934ff..eb6c3ff553bfa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -59,7 +59,7 @@ private static SourcePropertySymbol Create( bool isExpressionBodied = !hasAccessorList && GetArrowExpression(syntax) != null; - binder = binder.WithUnsafeRegionIfNecessary(modifiersTokenList); + binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiersTokenList); TypeSymbol? explicitInterfaceType; string? aliasQualifierOpt; string memberName = ExplicitInterfaceHelpers.GetMemberNameAndInterfaceSymbol(binder, explicitInterfaceSpecifier, name, diagnostics, out explicitInterfaceType, out aliasQualifierOpt); @@ -431,7 +431,7 @@ private Binder CreateBinderForTypeAndParameters() var binderFactory = compilation.GetBinderFactory(syntaxTree); var binder = binderFactory.GetBinder(syntax, syntax, this); SyntaxTokenList modifiers = GetModifierTokensSyntax(syntax); - binder = binder.WithUnsafeRegionIfNecessary(modifiers); + binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiers); return binder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); } From a79647ab99436e3ddaf25447b3786d8397da463f Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Fri, 26 Apr 2024 11:32:54 +0200 Subject: [PATCH 09/21] Improve code --- .../BinderFactory.BinderFactoryVisitor.cs | 27 +++++++++++++------ .../CSharp/Portable/Binder/BinderFactory.cs | 4 +++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 240efe35a5b3a..ae745f4765072 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -167,6 +167,7 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl } SourceMemberMethodSymbol method = null; + bool isIteratorBody = false; if (usage != NodeUsage.Normal && methodDecl.TypeParameterList != null) { @@ -177,11 +178,11 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl if (usage == NodeUsage.MethodBody) { method = method ?? GetMethodSymbol(methodDecl, resultBinder); + isIteratorBody = method.IsIterator; resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(methodDecl.Modifiers, - isIteratorBody: usage == NodeUsage.MethodBody && method?.IsIterator == true); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(methodDecl.Modifiers, isIteratorBody: isIteratorBody); binderCache.TryAdd(key, resultBinder); } @@ -215,6 +216,10 @@ public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax //TODO: the error should be given in a different place, but should we ignore or consider the type args? Debug.Assert(method.Arity == 0, "Generic Ctor, What to do?"); + // Constructor cannot be an iterator, otherwise we would need to pass + // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` below. + Debug.Assert(!method.IsIterator); + resultBinder = new InMethodBinder(method, resultBinder); } } @@ -246,6 +251,10 @@ public override Binder VisitDestructorDeclaration(DestructorDeclarationSyntax pa SourceMemberMethodSymbol method = GetMethodSymbol(parent, resultBinder); resultBinder = new InMethodBinder(method, resultBinder); + // Destructor cannot be an iterator, otherwise we would need to pass + // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` below. + Debug.Assert(!method.IsIterator); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); @@ -335,13 +344,14 @@ private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax resultBinder = VisitCore(parent.Parent); MethodSymbol method = GetMethodSymbol(parent, resultBinder); + bool isIteratorBody = false; if ((object)method != null && inBody) { + isIteratorBody = method.IsIterator; resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, - isIteratorBody: inBody && method?.IsIterator == true); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, isIteratorBody: isIteratorBody); binderCache.TryAdd(key, resultBinder); } @@ -401,18 +411,19 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta Binder resultBinder; if (!binderCache.TryGetValue(key, out resultBinder)) { - resultBinder = VisitCore(parent.Parent); + resultBinder = VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); var propertySymbol = GetPropertySymbol(parent, resultBinder); var accessor = propertySymbol.GetMethod; if ((object)accessor != null) { + // Expression body cannot be an iterator, otherwise we would need to pass + // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` above. + Debug.Assert(!accessor.IsIterator); + resultBinder = new InMethodBinder(accessor, resultBinder); } - resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, - isIteratorBody: accessor?.IsIterator == true); - binderCache.TryAdd(key, resultBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs index 7b588ae0fa4d1..0cd63c781e26b 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs @@ -151,6 +151,10 @@ internal InMethodBinder GetPrimaryConstructorInMethodBinder(SynthesizedPrimaryCo Debug.Assert(constructor.Arity == 0, "Generic Ctor, What to do?"); resultBinder = new InMethodBinder(constructor, GetInTypeBodyBinder(typeDecl)); + // Constructors cannot be an iterator, otherwise we would need to + // call `SetOrClearUnsafeRegionIfNecessary` and pass `isIteratorBody`. + Debug.Assert(!constructor.IsIterator); + _binderCache.TryAdd(key, resultBinder); } From c5f777080e221d139cace53c35d2b9d680d09e1d Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Fri, 26 Apr 2024 11:44:21 +0200 Subject: [PATCH 10/21] Fix accessors --- .../BinderFactory.BinderFactoryVisitor.cs | 4 +++ .../Test/Semantic/Semantics/UnsafeTests.cs | 26 ++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index ae745f4765072..ccaeae84fd5a8 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -317,6 +317,10 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent if ((object)accessor != null) { resultBinder = new InMethodBinder(accessor, resultBinder); + + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary( + modifiers: default, + isIteratorBody: accessor.IsIterator); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 7a43d6dbc3c60..c916792cdd15f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -1102,7 +1102,10 @@ public unsafe System.Collections.Generic.IEnumerable M get { int x = 1; - x = sizeof(nint); + unsafe + { + x = sizeof(nint); + } yield break; } set @@ -1129,7 +1132,7 @@ unsafe System.Collections.Generic.IEnumerable this[int x] { get // error in C# 12: unsafe code may not appear in iterators { - yield return 1; // error in C# 13: yield in unsafe context + yield return 1; } set { } } @@ -1141,15 +1144,8 @@ unsafe System.Collections.Generic.IEnumerable this[int x] // get // error in C# 12: unsafe code may not appear in iterators Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); - var expectedDiagnostics = new[] - { - // (7,13): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return 1; // error in C# 13: yield in unsafe context - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 13) - }; - - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -1867,9 +1863,9 @@ public unsafe A(int* p) { } // (11,15): error CS1637: Iterators cannot have pointer type parameters // this[int* p] Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), - // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // (13,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // get { yield return *p; } - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 29)); } else { @@ -1977,9 +1973,9 @@ public unsafe A(int* p) { } // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type // [A(null)] Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (13,15): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // (13,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(13, 15)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 28)); } else { From ce0140b5681c9926a85af2597eca2c92347827bd Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Fri, 26 Apr 2024 12:53:22 +0200 Subject: [PATCH 11/21] Remove asserts that can fail for invalid code --- .../Portable/Binder/BinderFactory.BinderFactoryVisitor.cs | 8 -------- src/Compilers/CSharp/Portable/Binder/BinderFactory.cs | 4 ---- 2 files changed, 12 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index ccaeae84fd5a8..dd5a9adf44764 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -216,10 +216,6 @@ public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax //TODO: the error should be given in a different place, but should we ignore or consider the type args? Debug.Assert(method.Arity == 0, "Generic Ctor, What to do?"); - // Constructor cannot be an iterator, otherwise we would need to pass - // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` below. - Debug.Assert(!method.IsIterator); - resultBinder = new InMethodBinder(method, resultBinder); } } @@ -251,10 +247,6 @@ public override Binder VisitDestructorDeclaration(DestructorDeclarationSyntax pa SourceMemberMethodSymbol method = GetMethodSymbol(parent, resultBinder); resultBinder = new InMethodBinder(method, resultBinder); - // Destructor cannot be an iterator, otherwise we would need to pass - // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` below. - Debug.Assert(!method.IsIterator); - resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs index 0cd63c781e26b..7b588ae0fa4d1 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs @@ -151,10 +151,6 @@ internal InMethodBinder GetPrimaryConstructorInMethodBinder(SynthesizedPrimaryCo Debug.Assert(constructor.Arity == 0, "Generic Ctor, What to do?"); resultBinder = new InMethodBinder(constructor, GetInTypeBodyBinder(typeDecl)); - // Constructors cannot be an iterator, otherwise we would need to - // call `SetOrClearUnsafeRegionIfNecessary` and pass `isIteratorBody`. - Debug.Assert(!constructor.IsIterator); - _binderCache.TryAdd(key, resultBinder); } From c4825083525af25cfcf83b998f79439041ae7972 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Mon, 29 Apr 2024 11:00:02 +0200 Subject: [PATCH 12/21] Improve tests --- .../Test/Semantic/Semantics/UnsafeTests.cs | 100 ++++++++++++++++-- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index c916792cdd15f..9c9f7a201efbb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -579,7 +579,7 @@ public void Iterator_UnsafeBlock_03() var code = """ class C { - public System.Collections.Generic.IEnumerable M() + public System.Collections.Generic.IEnumerable M(int*[] a) { int x; x = sizeof(nint); @@ -589,12 +589,18 @@ public System.Collections.Generic.IEnumerable M() """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,58): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public System.Collections.Generic.IEnumerable M(int*[] a) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 58), // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // x = sizeof(nint); Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); var expectedDiagnostics = new[] { + // (3,58): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public System.Collections.Generic.IEnumerable M(int*[] a) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 58), // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // x = sizeof(nint); Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) @@ -610,7 +616,7 @@ public void Iterator_UnsafeBlock_04() var code = """ unsafe class C { - public System.Collections.Generic.IEnumerable M() + public System.Collections.Generic.IEnumerable M(int*[] a) { int x; x = sizeof(nint); @@ -635,6 +641,40 @@ public System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void Iterator_UnsafeBlock_05() + { + var code = """ + class C + { + public unsafe System.Collections.Generic.IEnumerable M(int*[] a) + { + int x; + x = sizeof(nint); + yield return x; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public unsafe System.Collections.Generic.IEnumerable M(int*[] a) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), + // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); + + var expectedDiagnostics = new[] + { + // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Fact] public void Iterator_UnsafeBlock_YieldBreakOnly_01_Local() { @@ -648,8 +688,8 @@ public System.Collections.Generic.IEnumerable M() { int *p = &x; *p = *p + 1; + yield break; } - yield break; } } """; @@ -694,8 +734,8 @@ public System.Collections.Generic.IEnumerable M(int x) { int *p = &x; *p = *p + 1; + yield break; } - yield break; } } """; @@ -744,7 +784,10 @@ public System.Collections.Generic.IEnumerable M() x = sizeof(nint); } System.Console.Write("I" + x); - yield break; + unsafe + { + yield break; + } } } """; @@ -755,7 +798,10 @@ public System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17), + // (13,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 9)); var expectedOutput = "I" + IntPtr.Size; CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); @@ -799,8 +845,8 @@ public async System.Collections.Generic.IAsyncEnumerable M() { int *p = &x; *p = *p + 1; + yield break; } - yield break; } } """ + AsyncStreamsTypes; @@ -1340,6 +1386,46 @@ static System.Collections.Generic.IEnumerable G(int x) Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 30)); } + [Fact] + public void Iterator_LocalFunction_03() + { + var code = """ + class Program + { + static void F() + { + unsafe + { + static System.Collections.Generic.IEnumerable G(int x) + { + unsafe + { + x = sizeof(nint); + } + yield return x; + + unsafe + { + G2(new int*[0]); + static System.Collections.Generic.IEnumerable G2(int*[] x) + { + int y; + unsafe + { + y = *x[0]; + } + yield return y; + } + } + } + G(0); + } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + [Fact] public void UnsafeContext_01() { From f848432daf250246ccb94066fdff443012d40655 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Mon, 29 Apr 2024 11:48:29 +0200 Subject: [PATCH 13/21] Avoid some langversion errors that would still be errors in newer langversions --- .../CSharp/Portable/Binder/Binder_Unsafe.cs | 8 ++--- .../Test/Semantic/Semantics/UnsafeTests.cs | 31 +++---------------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs index a71d91573820e..2c4d9b6a7fb88 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs @@ -56,16 +56,16 @@ private CSDiagnosticInfo GetUnsafeDiagnosticInfo(TypeSymbol sizeOfTypeOpt) { return null; } - else if (this.IsIndirectlyInIterator && MessageID.IDS_FeatureRefUnsafeInIteratorAsync.GetFeatureAvailabilityDiagnosticInfo(Compilation) is { } unsafeInIteratorDiagnosticInfo) - { - return unsafeInIteratorDiagnosticInfo; - } else if (!this.InUnsafeRegion) { return ((object)sizeOfTypeOpt == null) ? new CSDiagnosticInfo(ErrorCode.ERR_UnsafeNeeded) : new CSDiagnosticInfo(ErrorCode.ERR_SizeofUnsafe, sizeOfTypeOpt); } + else if (this.IsIndirectlyInIterator && MessageID.IDS_FeatureRefUnsafeInIteratorAsync.GetFeatureAvailabilityDiagnosticInfo(Compilation) is { } unsafeInIteratorDiagnosticInfo) + { + return unsafeInIteratorDiagnosticInfo; + } else { return null; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 9c9f7a201efbb..016992809e50f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -588,14 +588,6 @@ public System.Collections.Generic.IEnumerable M(int*[] a) } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (3,58): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // public System.Collections.Generic.IEnumerable M(int*[] a) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 58), - // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); - var expectedDiagnostics = new[] { // (3,58): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context @@ -606,6 +598,7 @@ public System.Collections.Generic.IEnumerable M(int*[] a) Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) }; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } @@ -1502,11 +1495,6 @@ IEnumerable M() } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - var expectedDiagnostics = new[] { // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context @@ -1514,6 +1502,7 @@ IEnumerable M() Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) }; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } @@ -1533,11 +1522,6 @@ IEnumerable M() } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - var expectedDiagnostics = new[] { // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context @@ -1545,6 +1529,7 @@ IEnumerable M() Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) }; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } @@ -10172,10 +10157,6 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // yield return sizeof(S); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); var expectedDiagnostics = new[] { @@ -10184,6 +10165,7 @@ System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(S)").WithArguments("S").WithLocation(6, 22) }; + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } @@ -10548,10 +10530,6 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // var p = stackalloc int[1]; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "stackalloc int[1]").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17)); var expectedDiagnostics = new[] { @@ -10560,6 +10538,7 @@ System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int[1]").WithLocation(6, 17) }; + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } From cb4f1f735dbbdf41ae8aad055d8779ef381d86d6 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 11:44:13 +0200 Subject: [PATCH 14/21] Refactor tests --- .../Test/Semantic/Semantics/UnsafeTests.cs | 2363 ++++++++--------- 1 file changed, 1141 insertions(+), 1222 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 016992809e50f..709b078329ca0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -354,8 +354,52 @@ System.Collections.Generic.IEnumerator Goo() CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73280")] + public void Iterator_UnsafeBlock_LangVersion() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M1() + { + unsafe // langversion error in C# 12 + { + int* p = null; // unnecessary langversion error in C# 12 + } + yield break; + } + System.Collections.Generic.IEnumerable M2() + { + int* p = null; // necessary langversion error in C# 12 + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe // langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; // unnecessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), + // (13,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; // necessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 9)); + + var expectedDiagnostics = new[] + { + // (13,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; // necessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Fact] - public void Iterator_UnsafeBlock_01_Local() + public void Iterator_UnsafeBlock_Local() { var code = """ class C @@ -373,6 +417,7 @@ public System.Collections.Generic.IEnumerable M() } """; + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe @@ -402,7 +447,7 @@ public System.Collections.Generic.IEnumerable M() } [Fact] - public void Iterator_UnsafeBlock_01_Parameter() + public void Iterator_UnsafeBlock_Parameter() { var code = """ class C @@ -419,6 +464,7 @@ public System.Collections.Generic.IEnumerable M(int x) } """; + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe @@ -541,7 +587,7 @@ static System.Collections.Generic.IEnumerable F() } [Fact] - public void Iterator_UnsafeBlock_02() + public void Iterator_UnsafeBlock_SizeOf() { var code = """ foreach (var x in new C().M()) System.Console.Write(x); @@ -560,6 +606,7 @@ public System.Collections.Generic.IEnumerable M() } """; + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe @@ -574,113 +621,15 @@ public System.Collections.Generic.IEnumerable M() } [Fact] - public void Iterator_UnsafeBlock_03() - { - var code = """ - class C - { - public System.Collections.Generic.IEnumerable M(int*[] a) - { - int x; - x = sizeof(nint); - yield return x; - } - } - """; - - var expectedDiagnostics = new[] - { - // (3,58): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // public System.Collections.Generic.IEnumerable M(int*[] a) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 58), - // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) - }; - - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - } - - [Fact] - public void Iterator_UnsafeBlock_04() - { - var code = """ - unsafe class C - { - public System.Collections.Generic.IEnumerable M(int*[] a) - { - int x; - x = sizeof(nint); - yield return x; - } - } - """; - - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); - - var expectedDiagnostics = new[] - { - // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) - }; - - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - } - - [Fact] - public void Iterator_UnsafeBlock_05() - { - var code = """ - class C - { - public unsafe System.Collections.Generic.IEnumerable M(int*[] a) - { - int x; - x = sizeof(nint); - yield return x; - } - } - """; - - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe System.Collections.Generic.IEnumerable M(int*[] a) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), - // (6,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 13)); - - var expectedDiagnostics = new[] - { - // (6,13): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 13) - }; - - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - } - - [Fact] - public void Iterator_UnsafeBlock_YieldBreakOnly_01_Local() + public void Iterator_UnsafeBlock_YieldBreak() { var code = """ class C { public System.Collections.Generic.IEnumerable M() { - int x = 1; unsafe { - int *p = &x; - *p = *p + 1; yield break; } } @@ -688,46 +637,25 @@ public System.Collections.Generic.IEnumerable M() """; CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), - // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), - // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), - // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), - // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19)); - - var expectedDiagnostics = new[] - { - // (8,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. - // int *p = &x; - Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23) - }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] - public void Iterator_UnsafeBlock_YieldBreakOnly_01_Parameter() + public void Iterator_UnsafeBlock_YieldReturn() { var code = """ class C { - public System.Collections.Generic.IEnumerable M(int x) + public System.Collections.Generic.IEnumerable M() { unsafe { - int *p = &x; - *p = *p + 1; - yield break; + yield return 1; } } } @@ -736,25 +664,13 @@ public System.Collections.Generic.IEnumerable M(int x) CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), - // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), - // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), - // (8,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 14), - // (8,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 19)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); var expectedDiagnostics = new[] { - // (7,23): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. - // int *p = &x; - Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(7, 23) + // (7,13): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 13) }; CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); @@ -762,121 +678,7 @@ public System.Collections.Generic.IEnumerable M(int x) } [Fact] - public void Iterator_UnsafeBlock_YieldBreakOnly_02() - { - var code = """ - foreach (var x in new C().M()) System.Console.Write("F" + x); - - class C - { - public System.Collections.Generic.IEnumerable M() - { - int x; - unsafe - { - x = sizeof(nint); - } - System.Console.Write("I" + x); - unsafe - { - yield break; - } - } - } - """; - - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), - // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17), - // (13,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 9)); - - var expectedOutput = "I" + IntPtr.Size; - CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); - CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); - } - - [Fact] - public void Iterator_UnsafeBlock_YieldBreakOnly_03() - { - var code = """ - foreach (var x in new C().M()) System.Console.Write("F" + x); - - class C - { - public System.Collections.Generic.IEnumerable M() - { - int x; - unsafe - { - x = sizeof(nint); - System.Console.Write("I" + x); - yield break; - } - } - } - """; - CompileAndVerify(code, expectedOutput: "I" + IntPtr.Size, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); - } - - [Fact] - public void Iterator_UnsafeBlock_YieldBreakOnly_Async() - { - var code = """ - #pragma warning disable CS1998 // async method lacks awaits - class C - { - public async System.Collections.Generic.IAsyncEnumerable M() - { - int x = 1; - unsafe - { - int *p = &x; - *p = *p + 1; - yield break; - } - } - } - """ + AsyncStreamsTypes; - - CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9), - // (9,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 13), - // (9,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22), - // (9,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(9, 23), - // (10,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 14), - // (10,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 19)); - - var expectedDiagnostics = new[] - { - // (9,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(9, 23) - }; - - CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); - } - - [Fact] - public void Iterator_UnsafeBlock_Async() + public void Iterator_UnsafeBlock_Async_01() { var code = """ await foreach (var x in new C().M()) System.Console.Write(x); @@ -897,41 +699,16 @@ public async System.Collections.Generic.IAsyncEnumerable M() } """ + AsyncStreamsTypes; - CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (9,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe - Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 9), - // (11,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 13), - // (11,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int *p = &x; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 22), - // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), - // (12,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 14), - // (12,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 19)); - - var expectedOutput = "1"; - var expectedDiagnostics = new[] - { + var comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: "1", verify: Verification.Fails).VerifyDiagnostics( // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23) - }; - var comp = CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe); - CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); - comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); - CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23)); } + // Should behave equivalently to AwaitBetweenUnsafeBlocks. [Fact] - public void Iterator_UnsafeBlock_YieldBreak() + public void Iterator_UnsafeBlock_Async_02() { var code = """ class C @@ -978,7 +755,7 @@ public System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } - // Should behave equivalently to Iterator_UnsafeBlock_YieldBreak. + // Should behave equivalently to Iterator_UnsafeBlock_Async_02. [Fact] public void AwaitBetweenUnsafeBlocks() { @@ -1037,142 +814,666 @@ public async Task M() } [Fact] - public void Iterator_UnsafeBlock_YieldBreak_Async() + public void Iterator_LocalFunction_Nested() { var code = """ - await foreach (var x in new C().M()) System.Console.Write(x); - - class C + class Program { - public async System.Collections.Generic.IAsyncEnumerable M() + static void F() { - int x = 1; - await System.Threading.Tasks.Task.Yield(); unsafe { - int *p = &x; - *p = *p + 1; - } - yield return x; - await System.Threading.Tasks.Task.Yield(); - unsafe - { - int *p = &x; - *p = *p + 1; - } - yield return x; - unsafe - { - int *p = &x; - if (*p == 3) yield break; + static System.Collections.Generic.IEnumerable G(int x) + { + unsafe + { + x = sizeof(nint); + } + yield return x; + + unsafe + { + G2(new int*[0]); + static System.Collections.Generic.IEnumerable G2(int*[] x) + { + int y; + unsafe + { + y = *x[0]; + } + yield return y; + } + } + } + G(0); } - yield return x; } } - """ + AsyncStreamsTypes; + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LambdaInIterator_Async() + { + var code = """ + using System.Collections.Generic; + using System.Threading.Tasks; + unsafe class C + { + IEnumerable M() + { + yield return 1; + var lam = async () => await Task.Yield(); + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - these should ideally be langversion errors + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,31): error CS4004: Cannot await in an unsafe context + // var lam = async () => await Task.Yield(); + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(8, 31)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_Async() + { + var code = """ + using System.Collections.Generic; + using System.Threading.Tasks; + unsafe class C + { + IEnumerable M() + { + yield return 1; + local(); + async void local() { await Task.Yield(); } + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - these should ideally be langversion errors + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (9,30): error CS4004: Cannot await in an unsafe context + // async void local() { await Task.Yield(); } + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(9, 30)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LambdaInIterator_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + var lam = () => sizeof(nint); + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,25): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lam = () => sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 25)); - var expectedOutput = "110"; var expectedDiagnostics = new[] { - // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23), - // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), - // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. - // int *p = &x; - Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23) + // (6,25): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // var lam = () => sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 25) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (7,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 24) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeMethod) + { + if (!unsafeClass || !unsafeMethod) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M(int* p) { } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Signature_Safe() + { + var code = """ + class C + { + void M(int* p) { } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 12)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Body_Unsafe(bool unsafeClass, bool unsafeMethod) + { + if (!unsafeClass || !unsafeMethod) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} int M() + { + return sizeof(nint); + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Body_Safe() + { + var code = """ + class C + { + int M() + { + return sizeof(nint); + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16)); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Signature_UnsafeMethod(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 56)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Signature_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,51): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 51) }; - var comp = CreateCompilationWithTasksExtensions(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe); - CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); - comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); - CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22)); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 22)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Body_CSharp13(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Signature_Unsafe(bool unsafeClass, bool unsafeOperator) + { + if (!unsafeClass || !unsafeOperator) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeOperator ? "unsafe" : "")}} public static C operator+(C c, int* p) + { + return c; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Signature_Safe() + { + var code = """ + class C + { + public static C operator+(C c, int* p) + { + return c; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,36): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public static C operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 36)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Body_Unsafe(bool unsafeClass, bool unsafeOperator) + { + if (!unsafeClass || !unsafeOperator) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeOperator ? "unsafe" : "")}} public static int operator+(C c1, C c2) + { + return sizeof(nint); + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Body_Safe() + { + var code = """ + class C + { + public static int operator+(C c1, C c2) + { + return sizeof(nint); + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16)); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Iterator_Signature_UnsafeOperator(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + public static unsafe System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,78): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static unsafe System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "+").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 78)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Signature_Safe() + { + var code = """ + class C + { + public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,78): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 78) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22)); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return sizeof(nint); + } + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 22)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Iterator_Body_CSharp13(bool unsafeClass, bool unsafeIndexer) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Signature_Unsafe(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass || !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} int this[int* p] + { + get { return 0; } + set { } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Indexer_Signature_Safe() + { + var code = """ + class C + { + int this[int* p] + { + get { return 0; } + set { } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 14)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Body_Unsafe(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass || !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} int this[int x] + { + get { return sizeof(nint); } + set { int* p = null; } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] - public void Iterator_Property_01() + public void UnsafeContext_Indexer_Body_Safe() { var code = """ - var c = new C(); - c.M = new[] { 42 }; - foreach (var y in c.M) System.Console.Write("Y" + y); class C { - public System.Collections.Generic.IEnumerable M + int this[int x] { - get - { - int x = 1; - unsafe - { - x = sizeof(nint); - } - yield return x; - } - set - { - int x = 1; - unsafe - { - int *p = &x; - *p = *p + 1; - } - System.Console.Write("X" + x); - } + get { return sizeof(nint); } + set { int* p = null; } } } """; - CompileAndVerify(code, expectedOutput: "X2Y" + IntPtr.Size, options: TestOptions.UnsafeReleaseExe, - verify: Verification.Fails).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); } [Fact] - public void Iterator_Property_02() + public void UnsafeContext_Indexer_Iterator_Signature_UnsafeClass() { var code = """ - var c = new C(); - c.M = new[] { 42 }; - foreach (var y in c.M) System.Console.Write("Y" + y); - class C + unsafe class C { - public unsafe System.Collections.Generic.IEnumerable M + System.Collections.Generic.IEnumerable this[int*[] p] { - get - { - int x = 1; - unsafe - { - x = sizeof(nint); - } - yield break; - } - set - { - int x = 1; - int *p = &x; - *p = *p + 1; - System.Console.Write("X" + x); - } + get { yield break; } + set { } } } """; - CompileAndVerify(code, expectedOutput: "X2", options: TestOptions.UnsafeReleaseExe, - verify: Verification.Fails).VerifyDiagnostics(); + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Theory, CombinatorialData] - public void Iterator_Indexer_01(bool unsafeClass) + public void UnsafeContext_Indexer_Iterator_Signature_UnsafeIndexer(bool unsafeClass) { var code = $$""" {{(unsafeClass ? "unsafe" : "")}} class C { - unsafe System.Collections.Generic.IEnumerable this[int x] + unsafe System.Collections.Generic.IEnumerable this[int*[] p] { - get // error in C# 12: unsafe code may not appear in iterators - { - yield return 1; - } + get { yield break; } set { } } } @@ -1180,110 +1481,105 @@ unsafe System.Collections.Generic.IEnumerable this[int x] CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // get // error in C# 12: unsafe code may not appear in iterators + // get { yield break; } Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] - public void Iterator_UnsafeMethod_01() + public void UnsafeContext_Indexer_Iterator_Signature_Safe() { var code = """ - foreach (var x in new C().M()) System.Console.Write("E" + x); - class C { - public unsafe System.Collections.Generic.IEnumerable M() + System.Collections.Generic.IEnumerable this[int*[] p] { - System.Console.Write("I"); - yield break; - #pragma warning disable CS0162 // Unreachable code detected - System.Console.Write("B"); + get { yield break; } + set { } } } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (5,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe System.Collections.Generic.IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 63)); + var expectedDiagnostics = new[] + { + // (3,54): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable this[int*[] p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 54) + }; - var expectedOutput = "I"; - CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); - CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] - public void Iterator_UnsafeMethod_02() + public void UnsafeContext_Indexer_Iterator_Body_CSharp12_Safe() { var code = """ - foreach (var x in new C().M()) System.Console.Write("E" + x); - class C { - public unsafe System.Collections.Generic.IEnumerable M() + System.Collections.Generic.IEnumerable this[int x] { - int x = 1; - int *p = &x; - *p = *p + 1; - System.Console.Write("I" + x); - yield break; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - - var expectedDiagnostics = new[] - { - // (8,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int *p = &x; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int *").WithLocation(8, 9), - // (8,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int *p = &x; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(8, 18), - // (8,19): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. - // int *p = &x; - Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 19), - // (9,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(9, 10), - // (9,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // *p = *p + 1; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(9, 15) - }; - - CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); } [Fact] - public void Iterator_UnsafeMethod_03() + public void UnsafeContext_Indexer_Iterator_Body_CSharp12_Unsafe() { var code = """ - class C + unsafe class C { - public unsafe System.Collections.Generic.IEnumerable M() + System.Collections.Generic.IEnumerable this[int x] { - int x = sizeof(nint); - yield break; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe System.Collections.Generic.IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), - // (5,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); + // (5,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 28)); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass || !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} System.Collections.Generic.IEnumerable this[int x] + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; var expectedDiagnostics = new[] { - // (5,17): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // int x = sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 17) + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28) }; CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); @@ -1291,55 +1587,48 @@ public unsafe System.Collections.Generic.IEnumerable M() } [Fact] - public void Iterator_UnsafeMethod_04() + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Safe() { var code = """ class C { - public unsafe System.Collections.Generic.IEnumerable M() + System.Collections.Generic.IEnumerable this[int x] { - int x = sizeof(nint); - yield return x; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (3,63): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public unsafe System.Collections.Generic.IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 63), - // (5,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int x = sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 17)); - var expectedDiagnostics = new[] { - // (5,17): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // int x = sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 17) + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) }; CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } - [Fact] - public void Iterator_LocalFunction_01() + [Theory, CombinatorialData] + public void UnsafeContext_Property_Signature_Unsafe(bool unsafeClass, bool unsafeProperty) { - var code = """ - class Program + if (!unsafeClass || !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C { - static System.Collections.Generic.IEnumerable F() + {{(unsafeProperty ? "unsafe" : "")}} int* P { - unsafe - { - static void G(int x) - { - int* p = &x; - } - G(0); - } - yield break; + get { throw null; } + set { } } } """; @@ -1347,967 +1636,597 @@ static void G(int x) } [Fact] - public void Iterator_LocalFunction_02() + public void UnsafeContext_Property_Signature_Safe() { var code = """ - class Program + class C { - static void F() + int* P { - unsafe - { - static System.Collections.Generic.IEnumerable G(int x) - { - unsafe - { - int* p = &x; - } - yield return sizeof(nint); - yield break; - } - G(0); - } + get { throw null; } + set { } } } """; CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (11,31): error CS9232: The '&' operator cannot be used on parameters or local variables in iterator methods. - // int* p = &x; - Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(11, 31), - // (13,30): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 30)); + // (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* P + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 5)); } - [Fact] - public void Iterator_LocalFunction_03() + [Theory, CombinatorialData] + public void UnsafeContext_Property_Body_Unsafe(bool unsafeClass, bool unsafeProperty) { - var code = """ - class Program + if (!unsafeClass || !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C { - static void F() + {{(unsafeProperty ? "unsafe" : "")}} int P { - unsafe - { - static System.Collections.Generic.IEnumerable G(int x) - { - unsafe - { - x = sizeof(nint); - } - yield return x; - - unsafe - { - G2(new int*[0]); - static System.Collections.Generic.IEnumerable G2(int*[] x) - { - int y; - unsafe - { - y = *x[0]; - } - yield return y; - } - } - } - G(0); - } + get { return sizeof(nint); } + set { int* p = null; } } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] - public void UnsafeContext_01() + public void UnsafeContext_Property_Body_Safe() { var code = """ - using System.Collections.Generic; - using System.Threading.Tasks; - unsafe class C + class C { - IEnumerable M() + int P { - yield return 1; - var lam = async () => await Task.Yield(); - async void local() { await Task.Yield(); } - local(); + get { return sizeof(nint); } + set { int* p = null; } } } """; - - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (8,31): error CS4004: Cannot await in an unsafe context - // var lam = async () => await Task.Yield(); - Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(8, 31), - // (9,30): error CS4004: Cannot await in an unsafe context - // async void local() { await Task.Yield(); } - Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(9, 30)); - - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); } [Fact] - public void UnsafeContext_02() + public void UnsafeContext_Property_Iterator_Signature_UnsafeClass() { var code = """ - using System.Collections.Generic; unsafe class C { - IEnumerable M() + System.Collections.Generic.IEnumerable P { - int* p = null; - yield break; + get { yield break; } + set { } } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } - var expectedDiagnostics = new[] - { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) - }; + [Theory, CombinatorialData] + public void UnsafeContext_Property_Iterator_Signature_UnsafeIndexer(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable P + { + get { yield break; } + set { } + } + } + """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get { yield break; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] - public void UnsafeContext_03() + public void UnsafeContext_Property_Iterator_Signature_Safe() { var code = """ - using System.Collections.Generic; class C { - IEnumerable M() + System.Collections.Generic.IEnumerable P { - int* p = null; - yield break; + get { yield break; } + set { } } } """; var expectedDiagnostics = new[] { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + // (3,44): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable P + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 44) }; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] - public void UnsafeContext_04() + public void UnsafeContext_Property_Iterator_Body_CSharp12_Safe() { var code = """ - using System.Collections.Generic; class C { - IEnumerable M() + System.Collections.Generic.IEnumerable P { - int* p = null; - yield return 1; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - - var expectedDiagnostics = new[] - { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) - }; - - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); } [Fact] - public void UnsafeContext_05() + public void UnsafeContext_Property_Iterator_Body_CSharp12_Unsafe() { var code = """ - using System.Collections.Generic; unsafe class C { - IEnumerable M() + System.Collections.Generic.IEnumerable P { - int* p = null; - yield return 1; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - - var expectedDiagnostics = new[] - { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) - }; - - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 28)); } - [Fact] - public void UnsafeContext_06() + [Theory, CombinatorialData] + public void UnsafeContext_Property_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeProperty) { - var code = """ - using System.Collections.Generic; - unsafe class C + if (!unsafeClass || !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C { - unsafe IEnumerable M() + {{(unsafeProperty ? "unsafe" : "")}} System.Collections.Generic.IEnumerable P { - int* p = null; - yield return 1; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (4,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 29), - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - var expectedDiagnostics = new[] { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28) }; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] - public void UnsafeContext_07() + public void UnsafeContext_Property_Iterator_Body_CSharp13_Safe() { var code = """ - using System.Collections.Generic; - unsafe class C + class C { - unsafe IEnumerable M() + System.Collections.Generic.IEnumerable P { - int* p = null; - yield break; + get { yield return sizeof(nint); } + set { int* p = null; } } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (4,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // unsafe IEnumerable M() - Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 29), - // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // int* p = null; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); - var expectedDiagnostics = new[] { - // (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* p = null; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9) + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) }; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] - public void UnsafeContext_Method(bool unsafeClass, bool unsafeMethod) + public void UnsafeContext_LocalFunction_Signature_Unsafe(bool unsafeBlock, bool unsafeFunction) { + if (!unsafeBlock || !unsafeFunction) + { + return; + } + var code = $$""" - class A : System.Attribute + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} { - public unsafe A(int* p) { } + {{(unsafeFunction ? "unsafe" : "")}} void M(int* p) { } } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } - {{(unsafeClass ? "unsafe" : "")}} class C - { - [A(null)] - {{(unsafeMethod ? "unsafe" : "")}} - int* - M(int* p) - { - return p; - } - } + [Fact] + public void UnsafeContext_LocalFunction_Signature_Safe() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + void M(int* p) { } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), - // (11,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 7), - // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // return p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16)); - } + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (2,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void M(int* p) { } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8)); } [Theory, CombinatorialData] - public void UnsafeContext_Method_Iterator(bool unsafeClass, bool unsafeMethod) + public void UnsafeContext_LocalFunction_Body_Unsafe(bool unsafeBlock, bool unsafeFunction) { - var code = $$""" - class A : System.Attribute - { - public unsafe A(int* p) { } - } + if (!unsafeBlock || !unsafeFunction) + { + return; + } - {{(unsafeClass ? "unsafe" : "")}} class C + var code = $$""" + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} { - [A(null)] - {{(unsafeMethod ? "unsafe" : "")}} - System.Collections.Generic.IEnumerable - M(int* p) + {{(unsafeFunction ? "unsafe" : "")}} int M() { - yield return *p; + return sizeof(nint); } } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod) - { - // Signature is unsafe, body is safe. - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,12): error CS1637: Iterators cannot have pointer type parameters - // M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), - // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (11,7): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 7), - // (11,12): error CS1637: Iterators cannot have pointer type parameters - // M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 12), - // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); - } + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void UnsafeContext_Operator(bool unsafeClass, bool unsafeOperator) + [Fact] + public void UnsafeContext_LocalFunction_Body_Safe() { - var code = $$""" - class A : System.Attribute + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + int M() { - public unsafe A(int* p) { } + return sizeof(nint); } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (4,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 12)); + } - {{(unsafeClass ? "unsafe" : "")}} class C + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Signature_UnsafeBlock() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + unsafe { - [A(null)] - {{(unsafeOperator ? "unsafe" : "")}} - public static int* - operator+(C c, int* p) + System.Collections.Generic.IEnumerable M(int*[] p) { - return p; + yield break; } } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeOperator) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (10,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // public static int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 19), - // (11,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 20), - // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // return p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16)); - } + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } [Theory, CombinatorialData] - public void UnsafeContext_Operator_Iterator(bool unsafeClass, bool unsafeOperator) + public void UnsafeContext_LocalFunction_Iterator_Signature_UnsafeFunction(bool unsafeBlock) { var code = $$""" - class A : System.Attribute + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} { - public unsafe A(int* p) { } - } - - {{(unsafeClass ? "unsafe" : "")}} class C - { - [A(null)] - {{(unsafeOperator ? "unsafe" : "")}} - public static System.Collections.Generic.IEnumerable - operator+(C c, int* p) + unsafe System.Collections.Generic.IEnumerable M(int*[] p) { - yield return *p; + yield break; } } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeOperator) - { - // Signature is unsafe, body is safe. - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,25): error CS1637: Iterators cannot have pointer type parameters - // operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), - // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (11,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 20), - // (11,25): error CS1637: Iterators cannot have pointer type parameters - // operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 25), - // (13,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 23)); - } + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void UnsafeContext_Indexer(bool unsafeClass, bool unsafeIndexer) + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Signature_Safe() { - var code = $$""" - class A : System.Attribute - { - public unsafe A(int* p) { } - } - - {{(unsafeClass ? "unsafe" : "")}} class C + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + System.Collections.Generic.IEnumerable M(int*[] p) { - [A(null)] - {{(unsafeIndexer ? "unsafe" : "")}} - int* - this[int* p] - { - get => p; - set { p = value; } - } + yield break; } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeIndexer) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); - } - else + + var expectedDiagnostics = new[] { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), - // (11,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 10), - // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // get => p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 16), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { p = value; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 15), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { p = value; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p = value").WithLocation(14, 15), - // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { p = value; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value").WithLocation(14, 19)); - } + // (2,47): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 47) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } - [Theory, CombinatorialData] - public void UnsafeContext_Indexer_Iterator(bool unsafeClass, bool unsafeIndexer) + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp12_Safe() { - var code = $$""" - class A : System.Attribute + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + System.Collections.Generic.IEnumerable M() { - public unsafe A(int* p) { } + yield return sizeof(nint); } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (4,18): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 18)); + } - {{(unsafeClass ? "unsafe" : "")}} class C + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + unsafe { - [A(null)] - {{(unsafeIndexer ? "unsafe" : "")}} - System.Collections.Generic.IEnumerable - this[int* p] + System.Collections.Generic.IEnumerable M() { - get { yield return *p; } - set { p = null; } + yield return sizeof(nint); } } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeIndexer) - { - // Signature and setter is unsafe, getter is safe. - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (11,15): error CS1637: Iterators cannot have pointer type parameters - // this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), - // (13,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // get { yield return *p; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 29)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (11,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 10), - // (11,15): error CS1637: Iterators cannot have pointer type parameters - // this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(11, 15), - // (13,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // get { yield return *p; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(13, 29), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { p = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 15), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { p = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p = null").WithLocation(14, 15)); - } + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); } [Theory, CombinatorialData] - public void UnsafeContext_Property(bool unsafeClass, bool unsafeProperty) + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp13(bool unsafeBlock, bool unsafeFunction) { var code = $$""" - class A : System.Attribute - { - public unsafe A(int* p) { } - } - - {{(unsafeClass ? "unsafe" : "")}} class C + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} { - [A(null)] - {{(unsafeProperty ? "unsafe" : "")}} - int* - P + {{(unsafeFunction ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() { - get => null; - set { value = null; } + yield return sizeof(nint); } } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeProperty) - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6)); - } - else + + var expectedDiagnostics = new[] { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (10,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 5), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { value = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value").WithLocation(14, 15), - // (14,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // set { value = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "value = null").WithLocation(14, 15)); - } + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } - [Theory, CombinatorialData] - public void UnsafeContext_Property_Iterator(bool unsafeClass, bool unsafeProperty) + [Fact] + public void UnsafeContext_Lambda_Signature_Unsafe() { - var code = $$""" - class A : System.Attribute - { - public unsafe A(int* p) { } - } - - {{(unsafeClass ? "unsafe" : "")}} class C + var code = """ + unsafe { - [A(null)] - {{(unsafeProperty ? "unsafe" : "")}} - System.Collections.Generic.IEnumerable - P - { - get { yield return sizeof(nint); } - set { int x = sizeof(nint); } - } + var lam = (int* p) => { }; } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeProperty) - { - // Signature and setter is unsafe, getter is safe. - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (13,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 28)); - } - else - { - comp.VerifyDiagnostics( - // (8,6): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(8, 6), - // (8,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(8, 8), - // (13,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(13, 28), - // (14,23): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // set { int x = sizeof(nint); } - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(14, 23)); - } + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void UnsafeContext_LocalFunction(bool unsafeClass, bool unsafeMethod, bool unsafeBlock, bool unsafeLocalFunction) + [Fact] + public void UnsafeContext_Lambda_Signature_Safe() { - var code = $$""" - #pragma warning disable CS8321 // local function is never used - - class A : System.Attribute - { - public unsafe A(int* p) { } - } + var code = """ + var lam = (int* p) => { }; + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (1,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int* p) => { }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 12), + // (1,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int* p) => { }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 17)); + } - {{(unsafeClass ? "unsafe" : "")}} class C + [Fact] + public void UnsafeContext_Lambda_Body_Unsafe() + { + var code = """ + unsafe { - {{(unsafeMethod ? "unsafe" : "")}} void M() + var lam = () => { - {{(unsafeBlock ? "unsafe" : "")}} { - [A(null)] - {{(unsafeLocalFunction ? "unsafe" : "")}} - int* - local(int* p) - { - return p; - } - } - } + return sizeof(nint); + }; } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod || unsafeBlock || unsafeLocalFunction) - { - comp.VerifyDiagnostics( - // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14)); - } - else - { - comp.VerifyDiagnostics( - // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), - // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(13, 16), - // (15,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(15, 13), - // (16,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // local(int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(16, 19), - // (18,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // return p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 24)); - } + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void UnsafeContext_LocalFunction_Iterator(bool unsafeClass, bool unsafeMethod, bool unsafeBlock, bool unsafeLocalFunction) + [Fact] + public void UnsafeContext_Lambda_Body_Safe() { - var code = $$""" - #pragma warning disable CS8321 // local function is never used - - class A : System.Attribute + var code = """ + var lam = () => { - public unsafe A(int* p) { } - } + return sizeof(nint); + }; + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (3,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 12)); + } - {{(unsafeClass ? "unsafe" : "")}} class C + [Fact] + public void UnsafeContext_Lambda_Iterator_Signature_Unsafe() + { + var code = """ + unsafe { - {{(unsafeMethod ? "unsafe" : "")}} void M() + var lam = (int*[] p) => { - {{(unsafeBlock ? "unsafe" : "")}} { - [A(null)] - {{(unsafeLocalFunction ? "unsafe" : "")}} - System.Collections.Generic.IEnumerable - local(int* p) - { - yield return *p; - } - } - } + yield break; + }; } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod || unsafeBlock || unsafeLocalFunction) - { - // Signature is unsafe, body is safe. - comp.VerifyDiagnostics( - // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), - // (16,24): error CS1637: Iterators cannot have pointer type parameters - // local(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), - // (18,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 31)); - } - else + + var expectedDiagnostics = new[] { - comp.VerifyDiagnostics( - // (13,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(13, 14), - // (13,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(13, 16), - // (16,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // local(int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(16, 19), - // (16,24): error CS1637: Iterators cannot have pointer type parameters - // local(int* p) - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(16, 24), - // (18,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(18, 31)); - } + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield break; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } - [Theory, CombinatorialData] - public void UnsafeContext_Lambda(bool unsafeClass, bool unsafeMethod, bool unsafeBlock) + [Fact] + public void UnsafeContext_Lambda_Iterator_Signature_Safe() { - var code = $$""" - class A : System.Attribute + var code = """ + var lam = (int*[] p) => { - public unsafe A(int* p) { } - } + yield break; + }; + """; - {{(unsafeClass ? "unsafe" : "")}} class C + var expectedDiagnostics = new[] + { + // (1,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int*[] p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 12), + // (1,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int*[] p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 19), + // (3,5): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield break; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(3, 5) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Iterator_Body_Unsafe() + { + var code = """ + unsafe { - {{(unsafeMethod ? "unsafe" : "")}} void M() + var lam = () => { - {{(unsafeBlock ? "unsafe" : "")}} { - var lam = - [A(null)] - int* - (int* p) - => p; - } - } + yield return sizeof(nint); + }; } """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod || unsafeBlock) - { - comp.VerifyDiagnostics( - // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14)); - } - else + + var expectedDiagnostics = new[] { - comp.VerifyDiagnostics( - // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), - // (12,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(12, 16), - // (13,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // int* - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 13), - // (14,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // (int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(14, 14), - // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // (int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 19), - // (15,20): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // => p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(15, 20)); - } + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = [ + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9), + // (5,9): error CS9231: Cannot use 'yield return' in an 'unsafe' block + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(5, 9) + ]; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } - [Theory, CombinatorialData] - public void UnsafeContext_Lambda_Iterator(bool unsafeClass, bool unsafeMethod, bool unsafeBlock) + [Fact] + public void UnsafeContext_Lambda_Iterator_Body_Safe() { - var code = $$""" - class A : System.Attribute - { - public unsafe A(int* p) { } - } - - {{(unsafeClass ? "unsafe" : "")}} class C + var code = """ + var lam = () => { - {{(unsafeMethod ? "unsafe" : "")}} void M() - { - {{(unsafeBlock ? "unsafe" : "")}} { - var lam = - [A(null)] - System.Collections.Generic.IEnumerable - (int* p) => - { - yield return *p; - }; - } - } - } + yield return sizeof(nint); + }; """; - var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll); - if (unsafeClass || unsafeMethod || unsafeBlock) - { - // Lambda cannot be an iterator, hence it always inherits `unsafe`. - comp.VerifyDiagnostics( - // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), - // (14,22): error CS1643: Not all code paths return a value in lambda expression of type '' - // (int* p) => - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "").WithLocation(14, 22), - // (16,17): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression - // yield return *p; - Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(16, 17), - // (16,17): error CS9231: Cannot use 'yield return' in an 'unsafe' block - // yield return *p; - Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(16, 17)); - } - else + + var expectedDiagnostics = new[] { - comp.VerifyDiagnostics( - // (12,14): error CS0181: Attribute constructor parameter 'p' has type 'int*', which is not a valid attribute parameter type - // [A(null)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("p", "int*").WithLocation(12, 14), - // (12,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // [A(null)] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(12, 16), - // (14,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // (int* p) => - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(14, 14), - // (14,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // (int* p) => - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(14, 19), - // (14,22): error CS1643: Not all code paths return a value in lambda expression of type '' - // (int* p) => - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "").WithLocation(14, 22), - // (16,17): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression - // yield return *p; - Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(16, 17), - // (16,31): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context - // yield return *p; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(16, 31)); - } + // (3,5): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(3, 5), + // (3,18): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } [Fact] From 48173903995a7bc276c19dfebf530ae30d5eb5b9 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 14:11:26 +0200 Subject: [PATCH 15/21] Document a breaking change --- .../Compiler Breaking Changes - DotNet 9.md | 27 +++++++++++++++++++ .../Test/Semantic/Semantics/UnsafeTests.cs | 20 ++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md new file mode 100644 index 0000000000000..0b9cd956cdf28 --- /dev/null +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md @@ -0,0 +1,27 @@ +# This document lists known breaking changes in Roslyn after .NET 8 all the way to .NET 9. + +## Iterators introduce safe context in C# 13 and newer + +***Introduced in Visual Studio 2022 version 17.11*** + +Although the language spec states that iterators introduce a safe context, Roslyn does not implement that in C# 12 and lower. +This will change in C# 13 as part of [a feature which allows unsafe code in iterators](https://github.com/dotnet/roslyn/issues/72662). +The change does not break normal scenarios as it was disallowed to use unsafe constructs directly in iterators anyway. +However, it can break scenarios where an unsafe context was previously inherited into nested local functions, for example: + +```cs +unsafe class C // unsafe context +{ + System.Collections.Generic.IEnumerable M() // an iterator + { + yield return 1; + local(); + void local() + { + int* p = null; // allowed in C# 12; error in C# 13 + } + } +} +``` + +You can work around the break simply by adding the `unsafe` modifier to the local function. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 709b078329ca0..8934ca2edd5f7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -965,6 +965,26 @@ System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void UnsafeContext_LocalFunctionInIterator_Unsafe_BreakingChangeWorkaround() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local(); + unsafe void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + [Theory, CombinatorialData] public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeMethod) { From d0977cb9f9f6ee68668648d3f46e75328a76ed79 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 16:39:25 +0200 Subject: [PATCH 16/21] Fix theory conditions --- .../Test/Semantic/Semantics/UnsafeTests.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 8934ca2edd5f7..ec8672b588393 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -988,7 +988,7 @@ System.Collections.Generic.IEnumerable M() [Theory, CombinatorialData] public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeMethod) { - if (!unsafeClass || !unsafeMethod) + if (!unsafeClass && !unsafeMethod) { return; } @@ -1020,7 +1020,7 @@ void M(int* p) { } [Theory, CombinatorialData] public void UnsafeContext_Method_Body_Unsafe(bool unsafeClass, bool unsafeMethod) { - if (!unsafeClass || !unsafeMethod) + if (!unsafeClass && !unsafeMethod) { return; } @@ -1184,7 +1184,7 @@ public void UnsafeContext_Method_Iterator_Body_CSharp13(bool unsafeClass, bool u [Theory, CombinatorialData] public void UnsafeContext_Operator_Signature_Unsafe(bool unsafeClass, bool unsafeOperator) { - if (!unsafeClass || !unsafeOperator) + if (!unsafeClass && !unsafeOperator) { return; } @@ -1222,7 +1222,7 @@ class C [Theory, CombinatorialData] public void UnsafeContext_Operator_Body_Unsafe(bool unsafeClass, bool unsafeOperator) { - if (!unsafeClass || !unsafeOperator) + if (!unsafeClass && !unsafeOperator) { return; } @@ -1386,7 +1386,7 @@ public void UnsafeContext_Operator_Iterator_Body_CSharp13(bool unsafeClass, bool [Theory, CombinatorialData] public void UnsafeContext_Indexer_Signature_Unsafe(bool unsafeClass, bool unsafeIndexer) { - if (!unsafeClass || !unsafeIndexer) + if (!unsafeClass && !unsafeIndexer) { return; } @@ -1426,7 +1426,7 @@ int this[int* p] [Theory, CombinatorialData] public void UnsafeContext_Indexer_Body_Unsafe(bool unsafeClass, bool unsafeIndexer) { - if (!unsafeClass || !unsafeIndexer) + if (!unsafeClass && !unsafeIndexer) { return; } @@ -1579,7 +1579,7 @@ System.Collections.Generic.IEnumerable this[int x] [Theory, CombinatorialData] public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeIndexer) { - if (!unsafeClass || !unsafeIndexer) + if (!unsafeClass && !unsafeIndexer) { return; } @@ -1637,7 +1637,7 @@ System.Collections.Generic.IEnumerable this[int x] [Theory, CombinatorialData] public void UnsafeContext_Property_Signature_Unsafe(bool unsafeClass, bool unsafeProperty) { - if (!unsafeClass || !unsafeProperty) + if (!unsafeClass && !unsafeProperty) { return; } @@ -1677,7 +1677,7 @@ class C [Theory, CombinatorialData] public void UnsafeContext_Property_Body_Unsafe(bool unsafeClass, bool unsafeProperty) { - if (!unsafeClass || !unsafeProperty) + if (!unsafeClass && !unsafeProperty) { return; } @@ -1830,7 +1830,7 @@ System.Collections.Generic.IEnumerable P [Theory, CombinatorialData] public void UnsafeContext_Property_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeProperty) { - if (!unsafeClass || !unsafeProperty) + if (!unsafeClass && !unsafeProperty) { return; } @@ -1888,7 +1888,7 @@ System.Collections.Generic.IEnumerable P [Theory, CombinatorialData] public void UnsafeContext_LocalFunction_Signature_Unsafe(bool unsafeBlock, bool unsafeFunction) { - if (!unsafeBlock || !unsafeFunction) + if (!unsafeBlock && !unsafeFunction) { return; } @@ -1919,7 +1919,7 @@ void M(int* p) { } [Theory, CombinatorialData] public void UnsafeContext_LocalFunction_Body_Unsafe(bool unsafeBlock, bool unsafeFunction) { - if (!unsafeBlock || !unsafeFunction) + if (!unsafeBlock && !unsafeFunction) { return; } From 14e508cadcd4315b4de856e38e1c0635b0b9e2bd Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 16:59:58 +0200 Subject: [PATCH 17/21] Test non-iterator unsafe contexts in older language versions as well --- .../Test/Semantic/Semantics/UnsafeTests.cs | 168 +++++++++++++++--- 1 file changed, 144 insertions(+), 24 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index ec8672b588393..67c73a49279ed 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -999,6 +999,9 @@ public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeM {{(unsafeMethod ? "unsafe" : "")}} void M(int* p) { } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1011,10 +1014,17 @@ class C void M(int* p) { } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (3,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // void M(int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 12)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1034,6 +1044,9 @@ public void UnsafeContext_Method_Body_Unsafe(bool unsafeClass, bool unsafeMethod } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1049,10 +1062,17 @@ int M() } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // return sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -1198,6 +1218,9 @@ public void UnsafeContext_Operator_Signature_Unsafe(bool unsafeClass, bool unsaf } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1213,10 +1236,17 @@ class C } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (3,36): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // public static C operator+(C c, int* p) - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 36)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 36) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1236,6 +1266,9 @@ public void UnsafeContext_Operator_Body_Unsafe(bool unsafeClass, bool unsafeOper } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1251,10 +1284,17 @@ class C } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // return sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -1401,6 +1441,9 @@ public void UnsafeContext_Indexer_Signature_Unsafe(bool unsafeClass, bool unsafe } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1417,10 +1460,17 @@ int this[int* p] } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (3,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // int this[int* p] - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 14)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 14) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1441,6 +1491,9 @@ public void UnsafeContext_Indexer_Body_Unsafe(bool unsafeClass, bool unsafeIndex } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1457,13 +1510,20 @@ int this[int x] } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // get { return sizeof(nint); } Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // set { int* p = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -1652,6 +1712,9 @@ public void UnsafeContext_Property_Signature_Unsafe(bool unsafeClass, bool unsaf } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1668,10 +1731,17 @@ class C } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // int* P - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 5)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 5) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1692,6 +1762,9 @@ public void UnsafeContext_Property_Body_Unsafe(bool unsafeClass, bool unsafeProp } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } @@ -1708,13 +1781,20 @@ int P } } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // get { return sizeof(nint); } Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // set { int* p = null; } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -1900,6 +1980,9 @@ public void UnsafeContext_LocalFunction_Signature_Unsafe(bool unsafeBlock, bool {{(unsafeFunction ? "unsafe" : "")}} void M(int* p) { } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -1910,10 +1993,17 @@ public void UnsafeContext_LocalFunction_Signature_Safe() #pragma warning disable CS8321 // The local function 'M' is declared but never used void M(int* p) { } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (2,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // void M(int* p) { } - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] @@ -1934,6 +2024,9 @@ public void UnsafeContext_LocalFunction_Body_Unsafe(bool unsafeBlock, bool unsaf } } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -1947,10 +2040,17 @@ int M() return sizeof(nint); } """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (4,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // return sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 12)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -2088,6 +2188,9 @@ public void UnsafeContext_Lambda_Signature_Unsafe() var lam = (int* p) => { }; } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -2097,13 +2200,20 @@ public void UnsafeContext_Lambda_Signature_Safe() var code = """ var lam = (int* p) => { }; """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (1,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // var lam = (int* p) => { }; Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 12), // (1,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // var lam = (int* p) => { }; - Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 17) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -2118,6 +2228,9 @@ public void UnsafeContext_Lambda_Body_Unsafe() }; } """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } @@ -2130,10 +2243,17 @@ public void UnsafeContext_Lambda_Body_Safe() return sizeof(nint); }; """; - CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + + var expectedDiagnostics = new[] + { // (3,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // return sizeof(nint); - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 12)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } [Fact] From 81ef3aa84db78f2759b46810ade221b809f0c9b2 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 17:14:19 +0200 Subject: [PATCH 18/21] Fix tests demonstrating unsafe context in iterators in C# 12 --- .../Test/Semantic/Semantics/UnsafeTests.cs | 82 ++++++++++++------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 67c73a49279ed..2c0861655bd1e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -985,6 +985,37 @@ System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73280")] + public void UnsafeContext_LangVersion() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + int* p = null; + yield break; + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + var expectedDiagnostics = new[] + { + // (5,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(5, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Theory, CombinatorialData] public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeMethod) { @@ -1166,15 +1197,12 @@ unsafe class C { System.Collections.Generic.IEnumerable M() { - yield return sizeof(nint); + yield return local(); + int local() => sizeof(nint); } } """; - // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (5,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 22)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Theory, CombinatorialData] @@ -1388,15 +1416,12 @@ unsafe class C { public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) { - yield return sizeof(nint); + yield return local(); + int local() => sizeof(nint); } } """; - // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (5,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 22)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Theory, CombinatorialData] @@ -1624,16 +1649,16 @@ unsafe class C { System.Collections.Generic.IEnumerable this[int x] { - get { yield return sizeof(nint); } + get + { + yield return local(); + int local() => sizeof(nint); + } set { int* p = null; } } } """; - // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (5,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 28)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Theory, CombinatorialData] @@ -1895,16 +1920,16 @@ unsafe class C { System.Collections.Generic.IEnumerable P { - get { yield return sizeof(nint); } + get + { + yield return local(); + int local() => sizeof(nint); + } set { int* p = null; } } } """; - // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (5,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // get { yield return sizeof(nint); } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 28)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Theory, CombinatorialData] @@ -2143,15 +2168,12 @@ public void UnsafeContext_LocalFunction_Iterator_Body_CSharp12_Unsafe() { System.Collections.Generic.IEnumerable M() { - yield return sizeof(nint); + yield return local(); + int local() => sizeof(nint); } } """; - // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 - CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( - // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } [Theory, CombinatorialData] From 2fd98b5ad3896556bf11797f49bfd86ce3a3c1b8 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 17:18:46 +0200 Subject: [PATCH 19/21] Improve naming of tests verifying safe context of setters --- .../CSharp/Test/Semantic/Semantics/UnsafeTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 2c0861655bd1e..e63952d8f037b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -1662,7 +1662,7 @@ System.Collections.Generic.IEnumerable this[int x] } [Theory, CombinatorialData] - public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeIndexer) + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_UnsafeSetter(bool unsafeClass, bool unsafeIndexer) { if (!unsafeClass && !unsafeIndexer) { @@ -1692,7 +1692,7 @@ public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Unsafe(bool unsafeClass } [Fact] - public void UnsafeContext_Indexer_Iterator_Body_CSharp13_Safe() + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_SafeSetter() { var code = """ class C @@ -1933,7 +1933,7 @@ System.Collections.Generic.IEnumerable P } [Theory, CombinatorialData] - public void UnsafeContext_Property_Iterator_Body_CSharp13_Unsafe(bool unsafeClass, bool unsafeProperty) + public void UnsafeContext_Property_Iterator_Body_CSharp13_UnsafeSetter(bool unsafeClass, bool unsafeProperty) { if (!unsafeClass && !unsafeProperty) { @@ -1963,7 +1963,7 @@ public void UnsafeContext_Property_Iterator_Body_CSharp13_Unsafe(bool unsafeClas } [Fact] - public void UnsafeContext_Property_Iterator_Body_CSharp13_Safe() + public void UnsafeContext_Property_Iterator_Body_CSharp13_SafeSetter() { var code = """ class C From 974722ebfc91f75bc1a19e52f84a5a200215f662 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 30 Apr 2024 19:17:04 +0200 Subject: [PATCH 20/21] Clarify comment --- src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index 130a16dab4598..e594a2999aea2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -94,8 +94,9 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) { // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context. - // In C# 12 and below, we keep the behavior that nested iterator bodies (e.g., local functions) - // inherit the safe/unsafe context from their containing scope to avoid a breaking change. + // In C# 12 and below, we keep the (spec violating) behavior that iterator bodies inherit the safe/unsafe context + // from their containing scope. Since there are errors for unsafe constructs directly in iterators, + // this inherited unsafe context can be observed only in nested non-iterator local functions. var withoutUnsafe = isIteratorBody && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync); if (this.Flags.Includes(BinderFlags.UnsafeRegion)) From 9c48d3187e59baf6c0399bbf7262d71da11d98c5 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 2 May 2024 10:15:20 +0200 Subject: [PATCH 21/21] Fix test name --- src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index e63952d8f037b..2c2a8d1f423e4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -1842,7 +1842,7 @@ unsafe class C } [Theory, CombinatorialData] - public void UnsafeContext_Property_Iterator_Signature_UnsafeIndexer(bool unsafeClass) + public void UnsafeContext_Property_Iterator_Signature_UnsafeProperty(bool unsafeClass) { var code = $$""" {{(unsafeClass ? "unsafe" : "")}} class C