From be9a062c837f7895f7ec994a465229650f0cb7af Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 26 Oct 2020 14:13:49 -0700 Subject: [PATCH 1/6] Disallow pointer and restricted types for record parameters --- .../Portable/Binder/Binder_Expressions.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../Source/SourceMemberContainerSymbol.cs | 9 +++ .../Portable/xlf/CSharpResources.cs.xlf | 5 ++ .../Portable/xlf/CSharpResources.de.xlf | 5 ++ .../Portable/xlf/CSharpResources.es.xlf | 5 ++ .../Portable/xlf/CSharpResources.fr.xlf | 5 ++ .../Portable/xlf/CSharpResources.it.xlf | 5 ++ .../Portable/xlf/CSharpResources.ja.xlf | 5 ++ .../Portable/xlf/CSharpResources.ko.xlf | 5 ++ .../Portable/xlf/CSharpResources.pl.xlf | 5 ++ .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 ++ .../Portable/xlf/CSharpResources.ru.xlf | 5 ++ .../Portable/xlf/CSharpResources.tr.xlf | 5 ++ .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 ++ .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 ++ .../Test/Semantic/Semantics/RecordTests.cs | 62 +++++++++++++++++++ 18 files changed, 141 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 3778f2ba83eb6..5cd2a0ee953bf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -5936,7 +5936,7 @@ private BoundExpression BindDynamicMemberAccess( for (int i = 0; i < typeArgumentsWithAnnotations.Length; ++i) { var typeArgument = typeArgumentsWithAnnotations[i]; - if ((typeArgument.Type.IsPointerOrFunctionPointer()) || typeArgument.Type.IsRestrictedType()) + if (typeArgument.Type.IsPointerOrFunctionPointer() || typeArgument.Type.IsRestrictedType()) { // "The type '{0}' may not be used as a type argument" Error(diagnostics, ErrorCode.ERR_BadTypeArgument, typeArgumentsSyntax[i], typeArgument.Type); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index b8b4d39eda9cb..8b44052e419e8 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6576,6 +6576,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The loaded assembly references .NET Framework, which is not supported. + + The type '{0}' may not be used for a positional parameter of a record. + A function pointer cannot be called with named arguments. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 648e12a7336c0..be1ff90f66583 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1924,6 +1924,7 @@ internal enum ErrorCode ERR_EqualityContractRequiresGetter = 8906, + ERR_BadParameterTypeInRecord = 8908, #endregion diagnostics introduced for C# 9.0 // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 1412a595ad398..abac9003f9b40 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -3046,6 +3046,15 @@ private void AddSynthesizedRecordMembersIfNecessary(MembersAndInitializersBuilde { var existingOrAddedMembers = addProperties(ctor.Parameters); addDeconstruct(ctor, existingOrAddedMembers); + + foreach (var parameter in ctor.Parameters) + { + var parameterType = parameter.Type; + if (parameterType.IsPointerOrFunctionPointer() || parameterType.IsRestrictedType()) + { + diagnostics.Add(ErrorCode.ERR_BadParameterTypeInRecord, parameter.Locations[0], parameterType); + } + } } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index e09d8f7cd2bf7..5c43610bab3ca 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Neplatný operand pro porovnávací vzorek. Vyžaduje se hodnota, ale nalezeno: {0}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 1dd298dd9d02e..cfbd622a4b241 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Ungültiger Operand für die Musterübereinstimmung. Ein Wert ist erforderlich, gefunden wurde aber "{0}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 506a0b22c1935..0d2c32536f2a4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Operando no válido para la coincidencia de patrones. Se requería un valor, pero se encontró '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 722cd2525dbb7..099f7d7ed3034 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Opérande non valide pour les critères spéciaux ; la valeur nécessaire n'est pas celle trouvée, '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 5152ffb165b67..7e785cd00ce0a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. L'operando non è valido per i criteri di ricerca. È richiesto un valore ma è stato trovato '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index cd39a63773615..063c58c0d436a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. パターン マッチには使用できないオペランドです。値が必要ですが、'{0}' が見つかりました。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d6321aecceb1e..1538aaa025f4c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. 패턴 일치에 대한 피연산자가 잘못되었습니다. 값이 필요하지만 '{0}'을(를) 찾았습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index a7bc6e4176c3a..0a0724d6177bd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Nieprawidłowy operand dla dopasowania wzorca; wymagana jest wartość, a znaleziono „{0}”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 131f3c80d4478..537f466bc270c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Operando inválido para correspondência de padrão. Um valor era obrigatório, mas '{0}' foi encontrado. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 0bc32e06e2622..d5340ec082480 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Недопустимый операнд для сопоставления с шаблоном. Требуется значение, но найдено "{0}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 7f62684d63634..2f6acf5243763 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. Desen eşleşmesi için işlenen geçersiz. Değer gerekiyordu ancak '{0}' bulundu. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 58e36bd745b5d..afac2dca0c521 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. 用于模式匹配的操作数无效;需要值,但找到的是“{0}”。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 252193d5b051e..71a05ed92414d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -137,6 +137,11 @@ Operator '{0}' cannot be applied to operand '{1}' + + The type '{0}' may not be used for a positional parameter of a record. + The type '{0}' may not be used for a positional parameter of a record. + + Invalid operand for pattern match; value required, but found '{0}'. 模式比對運算元無效; 需要值,但找到 '{0}'。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 893344c53c686..33adce98c812b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -811,6 +811,68 @@ public void RecordProperties_10() ); } + [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)] + [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] + public void RestrictedTypesAndPointerTypes() + { + var src = @" +class C { } +static class C2 { } +ref struct RefLike{} + +unsafe record C( // 1 + int* P1, // 2 + int*[] P2, + C P3, + delegate* P4, // 3 + void P5, // 4 + C2 P6, // 5, 6 + System.ArgIterator P7, // 7, 8 + System.TypedReference P8, // 9, 10 + RefLike P9); // 11, 12 +"; + + var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (6,15): error CS0721: 'C2': static types cannot be used as parameters + // unsafe record C( // 1 + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C2").WithLocation(6, 15), + // (7,10): error CS8908: The type 'int*' may not be used for a positional parameter of a record. + // int* P1, // 2 + Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P1").WithArguments("int*").WithLocation(7, 10), + // (10,25): error CS8908: The type 'delegate*' may not be used for a positional parameter of a record. + // delegate* P4, // 3 + Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P4").WithArguments("delegate*").WithLocation(10, 25), + // (11,5): error CS1536: Invalid parameter type 'void' + // void P5, // 4 + Diagnostic(ErrorCode.ERR_NoVoidParameter, "void").WithLocation(11, 5), + // (12,8): error CS0722: 'C2': static types cannot be used as return types + // C2 P6, // 5, 6 + Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "P6").WithArguments("C2").WithLocation(12, 8), + // (12,8): error CS0721: 'C2': static types cannot be used as parameters + // C2 P6, // 5, 6 + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "P6").WithArguments("C2").WithLocation(12, 8), + // (13,5): error CS0610: Field or property cannot be of type 'ArgIterator' + // System.ArgIterator P7, // 7, 8 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 5), + // (13,24): error CS8908: The type 'ArgIterator' may not be used for a positional parameter of a record. + // System.ArgIterator P7, // 7, 8 + Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P7").WithArguments("System.ArgIterator").WithLocation(13, 24), + // (14,5): error CS0610: Field or property cannot be of type 'TypedReference' + // System.TypedReference P8, // 9, 10 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 5), + // (14,27): error CS8908: The type 'TypedReference' may not be used for a positional parameter of a record. + // System.TypedReference P8, // 9, 10 + Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P8").WithArguments("System.TypedReference").WithLocation(14, 27), + // (15,5): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. + // RefLike P9); // 11, 12 + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5), + // (15,13): error CS8908: The type 'RefLike' may not be used for a positional parameter of a record. + // RefLike P9); // 11, 12 + Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P9").WithArguments("RefLike").WithLocation(15, 13) + ); + } + [Fact] public void EmptyRecord_01() { From 7d84959022800b5124f110a62e1f5aa5dde3b521 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 27 Oct 2020 16:09:21 -0700 Subject: [PATCH 2/6] Address feedback from Aleksey --- .../CSharp/Portable/CSharpResources.resx | 4 +- .../CSharp/Portable/Errors/ErrorCode.cs | 2 +- .../Source/SourceMemberContainerSymbol.cs | 9 -- .../Records/SynthesizedRecordEquals.cs | 15 ++- .../Portable/xlf/CSharpResources.cs.xlf | 10 +- .../Portable/xlf/CSharpResources.de.xlf | 10 +- .../Portable/xlf/CSharpResources.es.xlf | 10 +- .../Portable/xlf/CSharpResources.fr.xlf | 10 +- .../Portable/xlf/CSharpResources.it.xlf | 10 +- .../Portable/xlf/CSharpResources.ja.xlf | 10 +- .../Portable/xlf/CSharpResources.ko.xlf | 10 +- .../Portable/xlf/CSharpResources.pl.xlf | 10 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 10 +- .../Portable/xlf/CSharpResources.ru.xlf | 10 +- .../Portable/xlf/CSharpResources.tr.xlf | 10 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 10 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 10 +- .../Test/Semantic/Semantics/RecordTests.cs | 108 ++++++++++++++++-- 18 files changed, 180 insertions(+), 88 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 8b44052e419e8..d8a077f53ef61 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6576,8 +6576,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The loaded assembly references .NET Framework, which is not supported. - - The type '{0}' may not be used for a positional parameter of a record. + + The type '{0}' may not be used for a field of a record. A function pointer cannot be called with named arguments. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index be1ff90f66583..690b35127a9a0 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1924,7 +1924,7 @@ internal enum ErrorCode ERR_EqualityContractRequiresGetter = 8906, - ERR_BadParameterTypeInRecord = 8908, + ERR_BadFieldTypeInRecord = 8908, #endregion diagnostics introduced for C# 9.0 // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index abac9003f9b40..1412a595ad398 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -3046,15 +3046,6 @@ private void AddSynthesizedRecordMembersIfNecessary(MembersAndInitializersBuilde { var existingOrAddedMembers = addProperties(ctor.Parameters); addDeconstruct(ctor, existingOrAddedMembers); - - foreach (var parameter in ctor.Parameters) - { - var parameterType = parameter.Type; - if (parameterType.IsPointerOrFunctionPointer() || parameterType.IsRestrictedType()) - { - diagnostics.Add(ErrorCode.ERR_BadParameterTypeInRecord, parameter.Locations[0], parameterType); - } - } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs index 9500036988f01..b2cca37c21bca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs @@ -125,14 +125,27 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, // field1 == other.field1 && ... && fieldN == other.fieldN var fields = ArrayBuilder.GetInstance(); + bool foundBadField = false; foreach (var f in ContainingType.GetFieldsToEmit()) { if (!f.IsStatic) { fields.Add(f); + + var parameterType = f.Type; + if (parameterType.IsPointerOrFunctionPointer()) + { + diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.Locations[0], parameterType); + foundBadField = true; + } + else if (parameterType.IsRestrictedType()) + { + // We'll have reported a diagnostic elsewhere (SourceMemberFieldSymbol.TypeChecks) + foundBadField = true; + } } } - if (fields.Count > 0) + if (fields.Count > 0 && !foundBadField) { retExpr = MethodBodySynthesizer.GenerateFieldEquals( retExpr, diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 5c43610bab3ca..1531ae1bea5ca 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -102,6 +102,11 @@ V asynchronním příkazu foreach nejde použít kolekce dynamického typu. + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Neplatný operand pro porovnávací vzorek. Vyžaduje se hodnota, ale nalezeno: {0}. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index cfbd622a4b241..ca9730647c3db 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -102,6 +102,11 @@ Eine Sammlung des dynamic-Typs kann in einem asynchronen foreach nicht verwendet werden. + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Ungültiger Operand für die Musterübereinstimmung. Ein Wert ist erforderlich, gefunden wurde aber "{0}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 0d2c32536f2a4..0b36f99ffce8a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -102,6 +102,11 @@ No se puede usar una colección de tipo dinámico en una instrucción foreach asincrónica. + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Operando no válido para la coincidencia de patrones. Se requería un valor, pero se encontró '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 099f7d7ed3034..3dbbe4a7d56f1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -102,6 +102,11 @@ Impossible d'utiliser une collection de type dynamique dans un foreach asynchrone + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Opérande non valide pour les critères spéciaux ; la valeur nécessaire n'est pas celle trouvée, '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 7e785cd00ce0a..7ef94d19e43e5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -102,6 +102,11 @@ Non è possibile usare una raccolta di tipo dinamico in un'istruzione foreach asincrona + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. L'operando non è valido per i criteri di ricerca. È richiesto un valore ma è stato trovato '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 063c58c0d436a..bc57e5688a9c9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -102,6 +102,11 @@ 非同期 foreach では動的な型のコレクションを使用できません + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. パターン マッチには使用できないオペランドです。値が必要ですが、'{0}' が見つかりました。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 1538aaa025f4c..d9b4f11d0acf1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -102,6 +102,11 @@ 비동기 foreach에는 동적 형식 컬렉션을 사용할 수 없습니다. + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. 패턴 일치에 대한 피연산자가 잘못되었습니다. 값이 필요하지만 '{0}'을(를) 찾았습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 0a0724d6177bd..641b7aca4bbd0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -102,6 +102,11 @@ Nie można użyć kolekcji typu dynamicznego w asynchronicznej instrukcji foreach + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Nieprawidłowy operand dla dopasowania wzorca; wymagana jest wartość, a znaleziono „{0}”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 537f466bc270c..8c8caa4d90d57 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -102,6 +102,11 @@ Não é possível usar uma coleção do tipo dinâmico em uma foreach assíncrona + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Operando inválido para correspondência de padrão. Um valor era obrigatório, mas '{0}' foi encontrado. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d5340ec082480..45ea3db32e177 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -102,6 +102,11 @@ Не удается использовать коллекцию динамического типа в асинхронном операторе foreach + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Недопустимый операнд для сопоставления с шаблоном. Требуется значение, но найдено "{0}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2f6acf5243763..3a9ac1d3421a8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -102,6 +102,11 @@ Zaman uyumsuz bir foreach içinde dinamik tür koleksiyonu oluşturulamaz + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. Desen eşleşmesi için işlenen geçersiz. Değer gerekiyordu ancak '{0}' bulundu. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index afac2dca0c521..d096d93144651 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -102,6 +102,11 @@ 无法在异步 foreach 中使用动态类型集合 + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. 用于模式匹配的操作数无效;需要值,但找到的是“{0}”。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 71a05ed92414d..76cfebdf64f33 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -102,6 +102,11 @@ 無法在非同步 foreach 中使用動態類型的集合 + + The type '{0}' may not be used for a field of a record. + The type '{0}' may not be used for a field of a record. + + Function pointer '{0}' does not take {1} arguments Function pointer '{0}' does not take {1} arguments @@ -137,11 +142,6 @@ Operator '{0}' cannot be applied to operand '{1}' - - The type '{0}' may not be used for a positional parameter of a record. - The type '{0}' may not be used for a positional parameter of a record. - - Invalid operand for pattern match; value required, but found '{0}'. 模式比對運算元無效; 需要值,但找到 '{0}'。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 33adce98c812b..1213fd94779d6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -837,12 +837,12 @@ unsafe record C( // 1 // (6,15): error CS0721: 'C2': static types cannot be used as parameters // unsafe record C( // 1 Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C2").WithLocation(6, 15), - // (7,10): error CS8908: The type 'int*' may not be used for a positional parameter of a record. + // (7,10): error CS8908: The type 'int*' may not be used for a field of a record. // int* P1, // 2 - Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P1").WithArguments("int*").WithLocation(7, 10), - // (10,25): error CS8908: The type 'delegate*' may not be used for a positional parameter of a record. + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P1").WithArguments("int*").WithLocation(7, 10), + // (10,25): error CS8908: The type 'delegate*' may not be used for a field of a record. // delegate* P4, // 3 - Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P4").WithArguments("delegate*").WithLocation(10, 25), + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P4").WithArguments("delegate*").WithLocation(10, 25), // (11,5): error CS1536: Invalid parameter type 'void' // void P5, // 4 Diagnostic(ErrorCode.ERR_NoVoidParameter, "void").WithLocation(11, 5), @@ -855,24 +855,112 @@ unsafe record C( // 1 // (13,5): error CS0610: Field or property cannot be of type 'ArgIterator' // System.ArgIterator P7, // 7, 8 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 5), - // (13,24): error CS8908: The type 'ArgIterator' may not be used for a positional parameter of a record. + // (13,24): error CS8908: The type 'ArgIterator' may not be used for a field of a record. // System.ArgIterator P7, // 7, 8 - Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P7").WithArguments("System.ArgIterator").WithLocation(13, 24), + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P7").WithArguments("System.ArgIterator").WithLocation(13, 24), // (14,5): error CS0610: Field or property cannot be of type 'TypedReference' // System.TypedReference P8, // 9, 10 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 5), - // (14,27): error CS8908: The type 'TypedReference' may not be used for a positional parameter of a record. + // (14,27): error CS8908: The type 'TypedReference' may not be used for a field of a record. // System.TypedReference P8, // 9, 10 - Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P8").WithArguments("System.TypedReference").WithLocation(14, 27), + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P8").WithArguments("System.TypedReference").WithLocation(14, 27), // (15,5): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. // RefLike P9); // 11, 12 Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5), - // (15,13): error CS8908: The type 'RefLike' may not be used for a positional parameter of a record. + // (15,13): error CS8908: The type 'RefLike' may not be used for a field of a record. // RefLike P9); // 11, 12 - Diagnostic(ErrorCode.ERR_BadParameterTypeInRecord, "P9").WithArguments("RefLike").WithLocation(15, 13) + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P9").WithArguments("RefLike").WithLocation(15, 13) ); } + [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)] + [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] + public void RestrictedTypesAndPointerTypes_NominalMembers() + { + var src = @" +#pragma warning disable 0649 +class C { } +static class C2 { } +ref struct RefLike{} + +unsafe record C +{ + public int* f1; // 1 + public int*[] f2; + public C f3; + public delegate* f4; // 2 + public void f5; // 3 + public C2 f6; // 4 + public System.ArgIterator f7; // 5 + public System.TypedReference f8; // 6 + public RefLike f9; // 7 +} +"; + + var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (9,17): error CS8908: The type 'int*' may not be used for a field of a record. + // public int* f1; // 1 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(9, 17), + // (12,32): error CS8908: The type 'delegate*' may not be used for a field of a record. + // public delegate* f4; // 2 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*").WithLocation(12, 32), + // (13,12): error CS0670: Field cannot have void type + // public void f5; // 3 + Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void").WithLocation(13, 12), + // (14,15): error CS0723: Cannot declare a variable of static type 'C2' + // public C2 f6; // 4 + Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(14, 15), + // (15,12): error CS0610: Field or property cannot be of type 'ArgIterator' + // public System.ArgIterator f7; // 5 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(15, 12), + // (16,12): error CS0610: Field or property cannot be of type 'TypedReference' + // public System.TypedReference f8; // 6 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(16, 12), + // (17,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. + // public RefLike f9; // 7 + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(17, 12) + ); + } + + [Fact] + [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] + public void RestrictedTypesAndPointerTypes_PointerTypeAllowedForParameterAndProperty() + { + var src = @" +class C { } + +unsafe record C(int* P1, int*[] P2, C P3) +{ + int* P1 + { + get { System.Console.Write(""P1 ""); return null; } + init { } + } + int*[] P2 + { + get { System.Console.Write(""P2 ""); return null; } + init { } + } + C P3 + { + get { System.Console.Write(""P3 ""); return null; } + init { } + } + + public unsafe static void Main() + { + var x = new C(null, null, null); + var (x1, x2, x3) = x; + System.Console.Write(""RAN""); + } +} +"; + var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugExe); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "P1 P2 P3 RAN"); + } + [Fact] public void EmptyRecord_01() { From 37857f510d62fd02d183126d476e91fdbfffae6f Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 27 Oct 2020 22:21:50 -0700 Subject: [PATCH 3/6] Add a test --- .../Test/Semantic/Semantics/RecordTests.cs | 76 ++++++++++++++----- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 1213fd94779d6..ad5e8c6ef906c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -878,12 +878,11 @@ unsafe record C( // 1 public void RestrictedTypesAndPointerTypes_NominalMembers() { var src = @" -#pragma warning disable 0649 -class C { } -static class C2 { } -ref struct RefLike{} +public class C { } +public static class C2 { } +public ref struct RefLike{} -unsafe record C +public unsafe record C { public int* f1; // 1 public int*[] f2; @@ -899,27 +898,27 @@ unsafe record C var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics( - // (9,17): error CS8908: The type 'int*' may not be used for a field of a record. + // (8,17): error CS8908: The type 'int*' may not be used for a field of a record. // public int* f1; // 1 - Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(9, 17), - // (12,32): error CS8908: The type 'delegate*' may not be used for a field of a record. + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(8, 17), + // (11,32): error CS8908: The type 'delegate*' may not be used for a field of a record. // public delegate* f4; // 2 - Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*").WithLocation(12, 32), - // (13,12): error CS0670: Field cannot have void type + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*").WithLocation(11, 32), + // (12,12): error CS0670: Field cannot have void type // public void f5; // 3 - Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void").WithLocation(13, 12), - // (14,15): error CS0723: Cannot declare a variable of static type 'C2' + Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void").WithLocation(12, 12), + // (13,15): error CS0723: Cannot declare a variable of static type 'C2' // public C2 f6; // 4 - Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(14, 15), - // (15,12): error CS0610: Field or property cannot be of type 'ArgIterator' + Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(13, 15), + // (14,12): error CS0610: Field or property cannot be of type 'ArgIterator' // public System.ArgIterator f7; // 5 - Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(15, 12), - // (16,12): error CS0610: Field or property cannot be of type 'TypedReference' + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(14, 12), + // (15,12): error CS0610: Field or property cannot be of type 'TypedReference' // public System.TypedReference f8; // 6 - Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(16, 12), - // (17,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(15, 12), + // (16,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. // public RefLike f9; // 7 - Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(17, 12) + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(16, 12) ); } @@ -961,6 +960,45 @@ public unsafe static void Main() CompileAndVerify(comp, expectedOutput: "P1 P2 P3 RAN"); } + [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)] + [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] + public void RestrictedTypesAndPointerTypes_StaticFields() + { + var src = @" +public class C { } +public static class C2 { } +public ref struct RefLike{} + +public unsafe record C +{ + public static int* f1; + public static int*[] f2; + public static C f3; + public static delegate* f4; + public static C2 f6; // 1 + public static System.ArgIterator f7; // 2 + public static System.TypedReference f8; // 3 + public static RefLike f9; // 4 +} +"; + + var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (12,22): error CS0723: Cannot declare a variable of static type 'C2' + // public static C2 f6; // 1 + Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(12, 22), + // (13,19): error CS0610: Field or property cannot be of type 'ArgIterator' + // public static System.ArgIterator f7; // 2 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 19), + // (14,19): error CS0610: Field or property cannot be of type 'TypedReference' + // public static System.TypedReference f8; // 3 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 19), + // (15,19): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. + // public static RefLike f9; // 4 + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 19) + ); + } + [Fact] public void EmptyRecord_01() { From e704f8499c943d5c15f0c9a05ceea0b87db76d0e Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 28 Oct 2020 23:46:37 -0700 Subject: [PATCH 4/6] Fix test --- .../Test/Semantic/Semantics/RecordTests.cs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index ad5e8c6ef906c..133f489803f16 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -827,9 +827,9 @@ unsafe record C( // 1 delegate* P4, // 3 void P5, // 4 C2 P6, // 5, 6 - System.ArgIterator P7, // 7, 8 - System.TypedReference P8, // 9, 10 - RefLike P9); // 11, 12 + System.ArgIterator P7, // 7 + System.TypedReference P8, // 8 + RefLike P9); // 9 "; var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); @@ -853,23 +853,14 @@ unsafe record C( // 1 // C2 P6, // 5, 6 Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "P6").WithArguments("C2").WithLocation(12, 8), // (13,5): error CS0610: Field or property cannot be of type 'ArgIterator' - // System.ArgIterator P7, // 7, 8 + // System.ArgIterator P7, // 7 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 5), - // (13,24): error CS8908: The type 'ArgIterator' may not be used for a field of a record. - // System.ArgIterator P7, // 7, 8 - Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P7").WithArguments("System.ArgIterator").WithLocation(13, 24), // (14,5): error CS0610: Field or property cannot be of type 'TypedReference' - // System.TypedReference P8, // 9, 10 + // System.TypedReference P8, // 8 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 5), - // (14,27): error CS8908: The type 'TypedReference' may not be used for a field of a record. - // System.TypedReference P8, // 9, 10 - Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P8").WithArguments("System.TypedReference").WithLocation(14, 27), // (15,5): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. - // RefLike P9); // 11, 12 - Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5), - // (15,13): error CS8908: The type 'RefLike' may not be used for a field of a record. - // RefLike P9); // 11, 12 - Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P9").WithArguments("RefLike").WithLocation(15, 13) + // RefLike P9); // 9 + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5) ); } @@ -957,7 +948,7 @@ public unsafe static void Main() "; var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugExe); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "P1 P2 P3 RAN"); + CompileAndVerify(comp, expectedOutput: "P1 P2 P3 RAN", verify: Verification.Skipped /* pointers */); } [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)] From aaea0bbe0e94b65496ea0ee7a5ed4c1b94312629 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 29 Oct 2020 10:37:57 -0700 Subject: [PATCH 5/6] Disallow unsafe types rather than pointer types --- .../Records/SynthesizedRecordEquals.cs | 2 +- .../Test/Semantic/Semantics/RecordTests.cs | 60 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs index b2cca37c21bca..ad15e2b60d233 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs @@ -133,7 +133,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, fields.Add(f); var parameterType = f.Type; - if (parameterType.IsPointerOrFunctionPointer()) + if (parameterType.IsUnsafe()) { diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.Locations[0], parameterType); foundBadField = true; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 133f489803f16..c900f823c2429 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -822,14 +822,14 @@ ref struct RefLike{} unsafe record C( // 1 int* P1, // 2 - int*[] P2, + int*[] P2, // 3 C P3, - delegate* P4, // 3 - void P5, // 4 - C2 P6, // 5, 6 - System.ArgIterator P7, // 7 - System.TypedReference P8, // 8 - RefLike P9); // 9 + delegate* P4, // 4 + void P5, // 5 + C2 P6, // 6, 7 + System.ArgIterator P7, // 8 + System.TypedReference P8, // 9 + RefLike P9); // 10 "; var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); @@ -840,26 +840,29 @@ unsafe record C( // 1 // (7,10): error CS8908: The type 'int*' may not be used for a field of a record. // int* P1, // 2 Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P1").WithArguments("int*").WithLocation(7, 10), + // (8,12): error CS8908: The type 'int*[]' may not be used for a field of a record. + // int*[] P2, // 3 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P2").WithArguments("int*[]").WithLocation(8, 12), // (10,25): error CS8908: The type 'delegate*' may not be used for a field of a record. - // delegate* P4, // 3 + // delegate* P4, // 4 Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P4").WithArguments("delegate*").WithLocation(10, 25), // (11,5): error CS1536: Invalid parameter type 'void' - // void P5, // 4 + // void P5, // 5 Diagnostic(ErrorCode.ERR_NoVoidParameter, "void").WithLocation(11, 5), // (12,8): error CS0722: 'C2': static types cannot be used as return types - // C2 P6, // 5, 6 + // C2 P6, // 6, 7 Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "P6").WithArguments("C2").WithLocation(12, 8), // (12,8): error CS0721: 'C2': static types cannot be used as parameters - // C2 P6, // 5, 6 + // C2 P6, // 6, 7 Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "P6").WithArguments("C2").WithLocation(12, 8), // (13,5): error CS0610: Field or property cannot be of type 'ArgIterator' - // System.ArgIterator P7, // 7 + // System.ArgIterator P7, // 8 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 5), // (14,5): error CS0610: Field or property cannot be of type 'TypedReference' - // System.TypedReference P8, // 8 + // System.TypedReference P8, // 9 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 5), // (15,5): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. - // RefLike P9); // 9 + // RefLike P9); // 10 Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5) ); } @@ -876,14 +879,14 @@ public ref struct RefLike{} public unsafe record C { public int* f1; // 1 - public int*[] f2; + public int*[] f2; // 2 public C f3; - public delegate* f4; // 2 - public void f5; // 3 - public C2 f6; // 4 - public System.ArgIterator f7; // 5 - public System.TypedReference f8; // 6 - public RefLike f9; // 7 + public delegate* f4; // 3 + public void f5; // 4 + public C2 f6; // 5 + public System.ArgIterator f7; // 6 + public System.TypedReference f8; // 7 + public RefLike f9; // 8 } "; @@ -892,23 +895,26 @@ public unsafe record C // (8,17): error CS8908: The type 'int*' may not be used for a field of a record. // public int* f1; // 1 Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(8, 17), + // (9,19): error CS8908: The type 'int*[]' may not be used for a field of a record. + // public int*[] f2; // 2 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f2").WithArguments("int*[]").WithLocation(9, 19), // (11,32): error CS8908: The type 'delegate*' may not be used for a field of a record. - // public delegate* f4; // 2 + // public delegate* f4; // 3 Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*").WithLocation(11, 32), // (12,12): error CS0670: Field cannot have void type - // public void f5; // 3 + // public void f5; // 4 Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void").WithLocation(12, 12), // (13,15): error CS0723: Cannot declare a variable of static type 'C2' - // public C2 f6; // 4 + // public C2 f6; // 5 Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(13, 15), // (14,12): error CS0610: Field or property cannot be of type 'ArgIterator' - // public System.ArgIterator f7; // 5 + // public System.ArgIterator f7; // 6 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(14, 12), // (15,12): error CS0610: Field or property cannot be of type 'TypedReference' - // public System.TypedReference f8; // 6 + // public System.TypedReference f8; // 7 Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(15, 12), // (16,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. - // public RefLike f9; // 7 + // public RefLike f9; // 8 Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(16, 12) ); } From 9529a5282ecc031b719902baaf72b12397b7ae98 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 30 Oct 2020 20:06:06 -0700 Subject: [PATCH 6/6] Add test --- .../Records/SynthesizedRecordEquals.cs | 2 +- .../Test/Semantic/Semantics/RecordTests.cs | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs index ad15e2b60d233..80e77faa87e1f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEquals.cs @@ -135,7 +135,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, var parameterType = f.Type; if (parameterType.IsUnsafe()) { - diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.Locations[0], parameterType); + diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.Locations.FirstOrNone(), parameterType); foundBadField = true; } else if (parameterType.IsRestrictedType()) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index c900f823c2429..88b0ab06c0aef 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -919,6 +919,61 @@ public unsafe record C ); } + [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)] + [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] + public void RestrictedTypesAndPointerTypes_NominalMembers_AutoProperties() + { + var src = @" +public class C { } +public static class C2 { } +public ref struct RefLike{} + +public unsafe record C +{ + public int* f1 { get; set; } // 1 + public int*[] f2 { get; set; } // 2 + public C f3 { get; set; } + public delegate* f4 { get; set; } // 3 + public void f5 { get; set; } // 4 + public C2 f6 { get; set; } // 5, 6 + public System.ArgIterator f7 { get; set; } // 6 + public System.TypedReference f8 { get; set; } // 7 + public RefLike f9 { get; set; } // 8 +} +"; + + var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (8,17): error CS8908: The type 'int*' may not be used for a field of a record. + // public int* f1 { get; set; } // 1 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(8, 17), + // (9,19): error CS8908: The type 'int*[]' may not be used for a field of a record. + // public int*[] f2 { get; set; } // 2 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f2").WithArguments("int*[]").WithLocation(9, 19), + // (11,32): error CS8908: The type 'delegate*' may not be used for a field of a record. + // public delegate* f4 { get; set; } // 3 + Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*").WithLocation(11, 32), + // (12,17): error CS0547: 'C.f5': property or indexer cannot have void type + // public void f5 { get; set; } // 4 + Diagnostic(ErrorCode.ERR_PropertyCantHaveVoidType, "f5").WithArguments("C.f5").WithLocation(12, 17), + // (13,20): error CS0722: 'C2': static types cannot be used as return types + // public C2 f6 { get; set; } // 5, 6 + Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "get").WithArguments("C2").WithLocation(13, 20), + // (13,25): error CS0721: 'C2': static types cannot be used as parameters + // public C2 f6 { get; set; } // 5, 6 + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "set").WithArguments("C2").WithLocation(13, 25), + // (14,12): error CS0610: Field or property cannot be of type 'ArgIterator' + // public System.ArgIterator f7 { get; set; } // 6 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(14, 12), + // (15,12): error CS0610: Field or property cannot be of type 'TypedReference' + // public System.TypedReference f8 { get; set; } // 7 + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(15, 12), + // (16,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct. + // public RefLike f9 { get; set; } // 8 + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(16, 12) + ); + } + [Fact] [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")] public void RestrictedTypesAndPointerTypes_PointerTypeAllowedForParameterAndProperty()