diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFlagsExtensions.cs b/src/Compilers/CSharp/Portable/Binder/BinderFlagsExtensions.cs index e437c80e8e535..144de3cc392ec 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFlagsExtensions.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFlagsExtensions.cs @@ -11,5 +11,10 @@ public static bool Includes(this BinderFlags self, BinderFlags other) { return (self & other) == other; } + + public static bool IncludesAny(this BinderFlags self, BinderFlags other) + { + return (self & other) != 0; + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 7bc3346493e5b..87c47dc836c8e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -339,7 +339,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre throw ExceptionUtilities.UnexpectedValue(conversion.Kind); } - var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, stackAllocType, boundStackAlloc.HasErrors); + var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, boundStackAlloc.InitializerOpt, stackAllocType, boundStackAlloc.HasErrors); var underlyingConversion = conversion.UnderlyingConversions.Single(); return CreateConversion(syntax, convertedNode, underlyingConversion, isCast, destination, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index b5e2811d66d11..f4cb3d8b7e356 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -383,6 +383,8 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic return BindImplicitArrayCreationExpression((ImplicitArrayCreationExpressionSyntax)node, diagnostics); case SyntaxKind.StackAllocArrayCreationExpression: return BindStackAllocArrayCreationExpression((StackAllocArrayCreationExpressionSyntax)node, diagnostics); + case SyntaxKind.ImplicitStackAllocArrayCreationExpression: + return BindImplicitStackAllocArrayCreationExpression((ImplicitStackAllocArrayCreationExpressionSyntax)node, diagnostics); case SyntaxKind.ObjectCreationExpression: return BindObjectCreationExpression((ObjectCreationExpressionSyntax)node, diagnostics); case SyntaxKind.IdentifierName: @@ -2714,6 +2716,40 @@ private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreatio sizes: ImmutableArray.Empty, boundInitExprOpt: boundInitializerExpressions); } + private BoundExpression BindImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics) + { + bool inLegalPosition = ReportBadStackAllocPosition(node, diagnostics); + bool hasErrors = !inLegalPosition; + + InitializerExpressionSyntax initializer = node.Initializer; + ImmutableArray boundInitializerExpressions = BindArrayInitializerExpressions(initializer, diagnostics, dimension: 1, rank: 1); + + HashSet useSiteDiagnostics = null; + TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, out bool hadMultipleCandidates, ref useSiteDiagnostics); + diagnostics.Add(node, useSiteDiagnostics); + + if ((object)bestType == null || bestType.SpecialType == SpecialType.System_Void) + { + Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, node); + bestType = CreateErrorType(); + } + + if (!bestType.IsErrorType() && bestType.IsManagedType) + { + Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, bestType); + } + + return BindStackAllocWithInitializer( + node, + initializer, + type: inLegalPosition ? GetStackAllocType(node, bestType, diagnostics) : null, + elementType: bestType, + sizeOpt: null, + diagnostics, + hasErrors, + boundInitializerExpressions); + } + // This method binds all the array initializer expressions. // NOTE: It doesn't convert the bound initializer expressions to array's element type. // NOTE: This is done separately in ConvertAndBindArrayInitialization method below. @@ -3032,25 +3068,8 @@ private BoundArrayCreation BindArrayCreationWithInitializer( private BoundExpression BindStackAllocArrayCreationExpression( StackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics) { - bool hasErrors = false; - var inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalSpanStackAllocPosition(); - - if (!inLegalPosition) - { - hasErrors = true; - diagnostics.Add( - ErrorCode.ERR_InvalidExprTerm, - node.StackAllocKeyword.GetLocation(), - SyntaxFacts.GetText(SyntaxKind.StackAllocKeyword)); - } - - // Check if we're syntactically within a catch or finally clause. - if (this.Flags.Includes(BinderFlags.InCatchBlock) || - this.Flags.Includes(BinderFlags.InCatchFilter) || - this.Flags.Includes(BinderFlags.InFinallyBlock)) - { - Error(diagnostics, ErrorCode.ERR_StackallocInCatchFinally, node); - } + bool inLegalPosition = ReportBadStackAllocPosition(node, diagnostics); + bool hasErrors = !inLegalPosition; TypeSyntax typeSyntax = node.Type; @@ -3070,24 +3089,22 @@ private BoundExpression BindStackAllocArrayCreationExpression( TypeSyntax elementTypeSyntax = arrayTypeSyntax.ElementType; TypeSymbol elementType = BindType(elementTypeSyntax, diagnostics); - bool typeHasErrors = elementType.IsErrorType(); - if (!typeHasErrors && elementType.IsManagedType) + if (!elementType.IsErrorType() && elementType.IsManagedType) { Error(diagnostics, ErrorCode.ERR_ManagedAddr, elementTypeSyntax, elementType); - typeHasErrors = true; + hasErrors = true; } SyntaxList rankSpecifiers = arrayTypeSyntax.RankSpecifiers; if (rankSpecifiers.Count != 1 || - rankSpecifiers[0].Sizes.Count != 1 || - rankSpecifiers[0].Sizes[0].Kind() == SyntaxKind.OmittedArraySizeExpression) + rankSpecifiers[0].Sizes.Count != 1) { // NOTE: Dev10 reported several parse errors here. Error(diagnostics, ErrorCode.ERR_BadStackAllocExpr, typeSyntax); var builder = ArrayBuilder.GetInstance(); - DiagnosticBag discardedDiagnostics = DiagnosticBag.GetInstance(); + var discardedDiagnostics = DiagnosticBag.GetInstance(); foreach (ArrayRankSpecifierSyntax rankSpecifier in rankSpecifiers) { foreach (ExpressionSyntax size in rankSpecifier.Sizes) @@ -3098,6 +3115,7 @@ private BoundExpression BindStackAllocArrayCreationExpression( } } } + discardedDiagnostics.Free(); return new BoundBadExpression( @@ -3108,21 +3126,61 @@ private BoundExpression BindStackAllocArrayCreationExpression( new PointerTypeSymbol(elementType)); } + TypeSymbol type = inLegalPosition ? GetStackAllocType(node, elementType, diagnostics) : null; + ExpressionSyntax countSyntax = rankSpecifiers[0].Sizes[0]; - var count = BindValue(countSyntax, diagnostics, BindValueKind.RValue); - if (!count.HasAnyErrors) + BoundExpression count = null; + if (countSyntax.Kind() != SyntaxKind.OmittedArraySizeExpression) { - // NOTE: this is different from how we would bind an array size (in which case we would allow uint, long, or ulong). - count = GenerateConversionForAssignment(GetSpecialType(SpecialType.System_Int32, diagnostics, node), count, diagnostics); - if (!count.HasAnyErrors && IsNegativeConstantForArraySize(count)) + count = BindValue(countSyntax, diagnostics, BindValueKind.RValue); + if (!count.HasAnyErrors) { - Error(diagnostics, ErrorCode.ERR_NegativeStackAllocSize, countSyntax); - hasErrors = true; + // NOTE: this is different from how we would bind an array size (in which case we would allow uint, long, or ulong). + count = GenerateConversionForAssignment(GetSpecialType(SpecialType.System_Int32, diagnostics, node), count, diagnostics); + if (!count.HasAnyErrors && IsNegativeConstantForArraySize(count)) + { + Error(diagnostics, ErrorCode.ERR_NegativeStackAllocSize, countSyntax); + hasErrors = true; + } } } + else if (node.Initializer == null) + { + // ERR_MissingArraySize is already reported + count = BadExpression(countSyntax); + hasErrors = true; + } - TypeSymbol type = null; - if (inLegalPosition && !node.IsVariableDeclarationInitialization()) + return node.Initializer == null + ? new BoundStackAllocArrayCreation(node, elementType, count, initializerOpt: null, type, hasErrors: hasErrors) + : BindStackAllocWithInitializer(node, node.Initializer, type, elementType, count, diagnostics, hasErrors); + } + + private bool ReportBadStackAllocPosition(SyntaxNode node, DiagnosticBag diagnostics) + { + Debug.Assert(node is StackAllocArrayCreationExpressionSyntax || node is ImplicitStackAllocArrayCreationExpressionSyntax); + + var inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalSpanStackAllocPosition(); + if (!inLegalPosition) + { + diagnostics.Add( + ErrorCode.ERR_InvalidExprTerm, + node.GetFirstToken().GetLocation(), + SyntaxFacts.GetText(SyntaxKind.StackAllocKeyword)); + } + + // Check if we're syntactically within a catch or finally clause. + if (this.Flags.IncludesAny(BinderFlags.InCatchBlock | BinderFlags.InCatchFilter | BinderFlags.InFinallyBlock)) + { + Error(diagnostics, ErrorCode.ERR_StackallocInCatchFinally, node); + } + + return inLegalPosition; + } + + private TypeSymbol GetStackAllocType(SyntaxNode node, TypeSymbol elementType, DiagnosticBag diagnostics) + { + if (!node.IsVariableDeclarationInitialization()) { CheckFeatureAvailability(node, MessageID.IDS_FeatureRefStructs, diagnostics); GetWellKnownTypeMember(Compilation, WellKnownMember.System_Span_T__ctor, diagnostics, syntax: node); @@ -3130,11 +3188,54 @@ private BoundExpression BindStackAllocArrayCreationExpression( var spanType = GetWellKnownType(WellKnownType.System_Span_T, diagnostics, node); if (!spanType.IsErrorType()) { - type = spanType.Construct(elementType); + return spanType.Construct(elementType); } } - return new BoundStackAllocArrayCreation(node, elementType, count, type, hasErrors: hasErrors || typeHasErrors); + return null; + } + + private BoundExpression BindStackAllocWithInitializer( + SyntaxNode node, + InitializerExpressionSyntax initSyntax, + TypeSymbol type, + TypeSymbol elementType, + BoundExpression sizeOpt, + DiagnosticBag diagnostics, + bool hasErrors, + ImmutableArray boundInitExprOpt = default) + { + if (boundInitExprOpt.IsDefault) + { + boundInitExprOpt = BindArrayInitializerExpressions(initSyntax, diagnostics, dimension: 1, rank: 1); + } + + boundInitExprOpt = boundInitExprOpt.SelectAsArray((expr, t) => GenerateConversionForAssignment(t.elementType, expr, t.diagnostics), (elementType, diagnostics)); + + if (sizeOpt != null) + { + int? constantSizeOpt = GetIntegerConstantForArraySize(sizeOpt); + if (!sizeOpt.HasAnyErrors && constantSizeOpt == null) + { + Error(diagnostics, ErrorCode.ERR_ConstantExpected, sizeOpt.Syntax); + hasErrors = true; + } + else if (boundInitExprOpt.Length != constantSizeOpt) + { + Error(diagnostics, ErrorCode.ERR_ArrayInitializerIncorrectLength, node, constantSizeOpt.Value); + hasErrors = true; + } + } + else + { + sizeOpt = new BoundLiteral( + node, + ConstantValue.Create(boundInitExprOpt.Length), + GetSpecialType(SpecialType.System_Int32, diagnostics, node)) + { WasCompilerGenerated = true }; + } + + return new BoundStackAllocArrayCreation(node, elementType, sizeOpt, new BoundArrayInitialization(initSyntax, boundInitExprOpt), type, hasErrors); } private static int? GetIntegerConstantForArraySize(BoundExpression expression) diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 560e88a72f770..d5e19103b1a14 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -1444,7 +1444,8 @@ - + + diff --git a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs index 3bb5642f6a3e7..0f9f30c193bac 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs @@ -149,7 +149,7 @@ internal partial class BoundStackAllocArrayCreation { public override object Display { - get { return string.Format(MessageID.IDS_StackAllocExpression.Localize().ToString(), ElementType, Count.Syntax); } + get { return string.Format(MessageID.IDS_StackAllocExpression.Localize().ToString(), ElementType, Count.WasCompilerGenerated ? null : Count.Syntax); } } } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 4f5b1d799f80c..a0980827131e8 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -10745,6 +10745,15 @@ internal static string IDS_FeatureRefStructs { } } + /// + /// Looks up a localized string similar to stackalloc initializer. + /// + internal static string IDS_FeatureStackAllocInitializer { + get { + return ResourceManager.GetString("IDS_FeatureStackAllocInitializer", resourceCulture); + } + } + /// /// Looks up a localized string similar to static classes. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3178e2140048f..e2e8c61b0d2ad 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5253,4 +5253,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Arguments with 'in' modifier cannot be used in dynamically dispatched expessions. - + + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 01dc17ea262b3..5e9885e1b3f35 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -1889,6 +1889,23 @@ private void EmitConvertedStackAllocExpression(BoundConvertedStackAllocExpressio { _builder.EmitOpCode(ILOpCode.Localloc); } + + var initializer = expression.InitializerOpt; + if (initializer != null) + { + if (used) + { + EmitStackAllocInitializers(expression.Type, initializer); + } + else + { + // If not used, just emit initializer elements to preserve possible sideeffects + foreach (var init in initializer.Initializers) + { + EmitExpression(init, used: false); + } + } + } } private void EmitObjectCreationExpression(BoundObjectCreationExpression expression, bool used) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs new file mode 100644 index 0000000000000..fa3e0c33e88fa --- /dev/null +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp.CodeGen +{ + internal partial class CodeGenerator + { + private void EmitStackAllocInitializers(TypeSymbol type, BoundArrayInitialization inits) + { + Debug.Assert(type is PointerTypeSymbol || type is NamedTypeSymbol); + + var elementType = type.TypeKind == TypeKind.Pointer + ? ((PointerTypeSymbol)type).PointedAtType + : ((NamedTypeSymbol)type).TypeArgumentsNoUseSiteDiagnostics[0]; + + var initExprs = inits.Initializers; + + var initializationStyle = ShouldEmitBlockInitializerForStackAlloc(elementType, initExprs); + if (initializationStyle == ArrayInitializerStyle.Element) + { + EmitElementStackAllocInitializers(elementType, initExprs, includeConstants: true); + } + else + { + ImmutableArray data = this.GetRawData(initExprs); + _builder.EmitStackAllocBlockInitializer(data, inits.Syntax, _diagnostics); + + if (initializationStyle == ArrayInitializerStyle.Mixed) + { + EmitElementStackAllocInitializers(elementType, initExprs, includeConstants: false); + } + } + } + + private ArrayInitializerStyle ShouldEmitBlockInitializerForStackAlloc(TypeSymbol elementType, ImmutableArray inits) + { + if (!_module.SupportsPrivateImplClass) + { + return ArrayInitializerStyle.Element; + } + + elementType = elementType.EnumUnderlyingType(); + + if (elementType.SpecialType.SizeInBytes() == 1) + { + int initCount = 0; + int constCount = 0; + StackAllocInitializerCount(inits, ref initCount, ref constCount); + + if (initCount > 2) + { + if (initCount == constCount) + { + return ArrayInitializerStyle.Block; + } + + int thresholdCnt = Math.Max(3, (initCount / 3)); + + if (constCount >= thresholdCnt) + { + return ArrayInitializerStyle.Mixed; + } + } + } + + return ArrayInitializerStyle.Element; + } + + private void StackAllocInitializerCount(ImmutableArray inits, ref int initCount, ref int constInits) + { + if (inits.Length == 0) + { + return; + } + + foreach (var init in inits) + { + Debug.Assert(!(init is BoundArrayInitialization), "Nested initializers are not allowed for stackalloc"); + + initCount += 1; + if (init.ConstantValue != null) + { + constInits += 1; + } + } + } + + private void EmitElementStackAllocInitializers(TypeSymbol elementType, ImmutableArray inits, bool includeConstants) + { + int index = 0; + int elementTypeSizeInBytes = elementType.SpecialType.SizeInBytes(); + foreach (BoundExpression init in inits) + { + if (includeConstants || init.ConstantValue == null) + { + _builder.EmitOpCode(ILOpCode.Dup); + EmitPointerElementAccess(init, elementType, elementTypeSizeInBytes, index); + EmitExpression(init, used: true); + EmitIndirectStore(elementType, init.Syntax); + } + + index++; + } + } + + private void EmitPointerElementAccess(BoundExpression init, TypeSymbol elementType, int elementTypeSizeInBytes, int index) + { + if (index == 0) + { + return; + } + + if (elementTypeSizeInBytes == 1) + { + _builder.EmitIntConstant(index); + _builder.EmitOpCode(ILOpCode.Add); + } + else if (index == 1) + { + EmitIntConstantOrSizeOf(init, elementType, elementTypeSizeInBytes); + _builder.EmitOpCode(ILOpCode.Add); + } + else + { + _builder.EmitIntConstant(index); + _builder.EmitOpCode(ILOpCode.Conv_i); + EmitIntConstantOrSizeOf(init, elementType, elementTypeSizeInBytes); + _builder.EmitOpCode(ILOpCode.Mul); + _builder.EmitOpCode(ILOpCode.Add); + } + } + + private void EmitIntConstantOrSizeOf(BoundExpression init, TypeSymbol elementType, int elementTypeSizeInBytes) + { + if (elementTypeSizeInBytes == 0) + { + _builder.EmitOpCode(ILOpCode.Sizeof); + EmitSymbolToken(elementType, init.Syntax); + } + else + { + _builder.EmitIntConstant(elementTypeSizeInBytes); + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 3cc8de8a2d211..77aaf796b9a1e 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -148,6 +148,7 @@ internal enum MessageID IDS_FeatureRefConditional = MessageBase + 12731, IDS_FeatureAttributesOnBackingFields = MessageBase + 12732, + IDS_FeatureStackAllocInitializer = MessageBase + 12733, } // Message IDs may refer to strings that need to be localized. @@ -189,6 +190,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) { // C# 7.3 features. case MessageID.IDS_FeatureAttributesOnBackingFields: // semantic check + case MessageID.IDS_FeatureStackAllocInitializer: return LanguageVersion.CSharp7_3; // C# 7.2 features. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs index e6f14fe27664b..5ea5170596d6f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs @@ -2576,12 +2576,22 @@ public override BoundNode VisitSizeOfOperator(BoundSizeOfOperator node) public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node) { VisitRvalue(node.Count); + + if (node.InitializerOpt != null && !node.InitializerOpt.Initializers.IsDefault) + { + foreach (var element in node.InitializerOpt.Initializers) + { + VisitRvalue(element); + } + } + + if (_trackExceptions) NotePossibleException(node); return null; } public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node) { - VisitRvalue(node.Count); + VisitStackAllocArrayCreation(node); return null; } diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index e3dad0c56ab48..76063d9131f70 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -5246,7 +5246,7 @@ public BoundArrayInitialization Update(ImmutableArray initializ internal partial class BoundStackAllocArrayCreation : BoundExpression { - protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false) + protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, BoundArrayInitialization initializerOpt, TypeSymbol type, bool hasErrors = false) : base(kind, syntax, type, hasErrors) { @@ -5255,10 +5255,11 @@ protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSy this.ElementType = elementType; this.Count = count; + this.InitializerOpt = initializerOpt; } - public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false) - : base(BoundKind.StackAllocArrayCreation, syntax, type, hasErrors || count.HasErrors()) + public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, BoundArrayInitialization initializerOpt, TypeSymbol type, bool hasErrors = false) + : base(BoundKind.StackAllocArrayCreation, syntax, type, hasErrors || count.HasErrors() || initializerOpt.HasErrors()) { Debug.Assert(elementType != null, "Field 'elementType' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); @@ -5266,6 +5267,7 @@ public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, B this.ElementType = elementType; this.Count = count; + this.InitializerOpt = initializerOpt; } @@ -5273,16 +5275,18 @@ public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, B public BoundExpression Count { get; } + public BoundArrayInitialization InitializerOpt { get; } + public override BoundNode Accept(BoundTreeVisitor visitor) { return visitor.VisitStackAllocArrayCreation(this); } - public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpression count, TypeSymbol type) + public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpression count, BoundArrayInitialization initializerOpt, TypeSymbol type) { - if (elementType != this.ElementType || count != this.Count || type != this.Type) + if (elementType != this.ElementType || count != this.Count || initializerOpt != this.InitializerOpt || type != this.Type) { - var result = new BoundStackAllocArrayCreation(this.Syntax, elementType, count, type, this.HasErrors); + var result = new BoundStackAllocArrayCreation(this.Syntax, elementType, count, initializerOpt, type, this.HasErrors); result.WasCompilerGenerated = this.WasCompilerGenerated; return result; } @@ -5292,8 +5296,8 @@ public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpressi internal sealed partial class BoundConvertedStackAllocExpression : BoundStackAllocArrayCreation { - public BoundConvertedStackAllocExpression(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false) - : base(BoundKind.ConvertedStackAllocExpression, syntax, elementType, count, type, hasErrors || count.HasErrors()) + public BoundConvertedStackAllocExpression(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, BoundArrayInitialization initializerOpt, TypeSymbol type, bool hasErrors = false) + : base(BoundKind.ConvertedStackAllocExpression, syntax, elementType, count, initializerOpt, type, hasErrors || count.HasErrors() || initializerOpt.HasErrors()) { Debug.Assert(elementType != null, "Field 'elementType' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); @@ -5308,11 +5312,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor) return visitor.VisitConvertedStackAllocExpression(this); } - public new BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, TypeSymbol type) + public new BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, BoundArrayInitialization initializerOpt, TypeSymbol type) { - if (elementType != this.ElementType || count != this.Count || type != this.Type) + if (elementType != this.ElementType || count != this.Count || initializerOpt != this.InitializerOpt || type != this.Type) { - var result = new BoundConvertedStackAllocExpression(this.Syntax, elementType, count, type, this.HasErrors); + var result = new BoundConvertedStackAllocExpression(this.Syntax, elementType, count, initializerOpt, type, this.HasErrors); result.WasCompilerGenerated = this.WasCompilerGenerated; return result; } @@ -8327,11 +8331,13 @@ public override BoundNode VisitArrayInitialization(BoundArrayInitialization node public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node) { this.Visit(node.Count); + this.Visit(node.InitializerOpt); return null; } public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node) { this.Visit(node.Count); + this.Visit(node.InitializerOpt); return null; } public override BoundNode VisitFieldAccess(BoundFieldAccess node) @@ -9190,16 +9196,18 @@ public override BoundNode VisitArrayInitialization(BoundArrayInitialization node public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node) { BoundExpression count = (BoundExpression)this.Visit(node.Count); + BoundArrayInitialization initializerOpt = (BoundArrayInitialization)this.Visit(node.InitializerOpt); TypeSymbol elementType = this.VisitType(node.ElementType); TypeSymbol type = this.VisitType(node.Type); - return node.Update(elementType, count, type); + return node.Update(elementType, count, initializerOpt, type); } public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node) { BoundExpression count = (BoundExpression)this.Visit(node.Count); + BoundArrayInitialization initializerOpt = (BoundArrayInitialization)this.Visit(node.InitializerOpt); TypeSymbol elementType = this.VisitType(node.ElementType); TypeSymbol type = this.VisitType(node.Type); - return node.Update(elementType, count, type); + return node.Update(elementType, count, initializerOpt, type); } public override BoundNode VisitFieldAccess(BoundFieldAccess node) { @@ -10656,6 +10664,7 @@ public override TreeDumperNode VisitStackAllocArrayCreation(BoundStackAllocArray { new TreeDumperNode("elementType", node.ElementType, null), new TreeDumperNode("count", null, new TreeDumperNode[] { Visit(node.Count, null) }), + new TreeDumperNode("initializerOpt", null, new TreeDumperNode[] { Visit(node.InitializerOpt, null) }), new TreeDumperNode("type", node.Type, null) } ); @@ -10666,6 +10675,7 @@ public override TreeDumperNode VisitConvertedStackAllocExpression(BoundConverted { new TreeDumperNode("elementType", node.ElementType, null), new TreeDumperNode("count", null, new TreeDumperNode[] { Visit(node.Count, null) }), + new TreeDumperNode("initializerOpt", null, new TreeDumperNode[] { Visit(node.InitializerOpt, null) }), new TreeDumperNode("type", node.Type, null) } ); diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs index 2612aff81df34..a6938d53ed7ac 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs @@ -8076,44 +8076,62 @@ internal sealed partial class StackAllocArrayCreationExpressionSyntax : Expressi { internal readonly SyntaxToken stackAllocKeyword; internal readonly TypeSyntax type; + internal readonly InitializerExpressionSyntax initializer; - internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) + internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) : base(kind, diagnostics, annotations) { - this.SlotCount = 2; + this.SlotCount = 3; this.AdjustFlagsAndWidth(stackAllocKeyword); this.stackAllocKeyword = stackAllocKeyword; this.AdjustFlagsAndWidth(type); this.type = type; + if (initializer != null) + { + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } } - internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type, SyntaxFactoryContext context) + internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer, SyntaxFactoryContext context) : base(kind) { this.SetFactoryContext(context); - this.SlotCount = 2; + this.SlotCount = 3; this.AdjustFlagsAndWidth(stackAllocKeyword); this.stackAllocKeyword = stackAllocKeyword; this.AdjustFlagsAndWidth(type); this.type = type; + if (initializer != null) + { + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } } - internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type) + internal StackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) : base(kind) { - this.SlotCount = 2; + this.SlotCount = 3; this.AdjustFlagsAndWidth(stackAllocKeyword); this.stackAllocKeyword = stackAllocKeyword; this.AdjustFlagsAndWidth(type); this.type = type; + if (initializer != null) + { + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } } /// SyntaxToken representing the stackalloc keyword. public SyntaxToken StackAllocKeyword { get { return this.stackAllocKeyword; } } /// TypeSyntax node representing the type of the stackalloc array. public TypeSyntax Type { get { return this.type; } } + /// InitializerExpressionSyntax node representing the initializer of the stackalloc array creation expression. + public InitializerExpressionSyntax Initializer { get { return this.initializer; } } internal override GreenNode GetSlot(int index) { @@ -8121,6 +8139,7 @@ internal override GreenNode GetSlot(int index) { case 0: return this.stackAllocKeyword; case 1: return this.type; + case 2: return this.initializer; default: return null; } } @@ -8140,11 +8159,11 @@ public override void Accept(CSharpSyntaxVisitor visitor) visitor.VisitStackAllocArrayCreationExpression(this); } - public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, TypeSyntax type) + public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) { - if (stackAllocKeyword != this.StackAllocKeyword || type != this.Type) + if (stackAllocKeyword != this.StackAllocKeyword || type != this.Type || initializer != this.Initializer) { - var newNode = SyntaxFactory.StackAllocArrayCreationExpression(stackAllocKeyword, type); + var newNode = SyntaxFactory.StackAllocArrayCreationExpression(stackAllocKeyword, type, initializer); var diags = this.GetDiagnostics(); if (diags != null && diags.Length > 0) newNode = newNode.WithDiagnosticsGreen(diags); @@ -8159,18 +8178,18 @@ public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyw internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) { - return new StackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.type, diagnostics, GetAnnotations()); + return new StackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.type, this.initializer, diagnostics, GetAnnotations()); } internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) { - return new StackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.type, GetDiagnostics(), annotations); + return new StackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.type, this.initializer, GetDiagnostics(), annotations); } internal StackAllocArrayCreationExpressionSyntax(ObjectReader reader) : base(reader) { - this.SlotCount = 2; + this.SlotCount = 3; var stackAllocKeyword = (SyntaxToken)reader.ReadValue(); if (stackAllocKeyword != null) { @@ -8183,6 +8202,12 @@ internal StackAllocArrayCreationExpressionSyntax(ObjectReader reader) AdjustFlagsAndWidth(type); this.type = type; } + var initializer = (InitializerExpressionSyntax)reader.ReadValue(); + if (initializer != null) + { + AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } } internal override void WriteTo(ObjectWriter writer) @@ -8190,6 +8215,7 @@ internal override void WriteTo(ObjectWriter writer) base.WriteTo(writer); writer.WriteValue(this.stackAllocKeyword); writer.WriteValue(this.type); + writer.WriteValue(this.initializer); } static StackAllocArrayCreationExpressionSyntax() @@ -8198,6 +8224,167 @@ static StackAllocArrayCreationExpressionSyntax() } } + /// Class which represents the syntax node for implicit stackalloc array creation expression. + internal sealed partial class ImplicitStackAllocArrayCreationExpressionSyntax : ExpressionSyntax + { + internal readonly SyntaxToken stackAllocKeyword; + internal readonly SyntaxToken openBracketToken; + internal readonly SyntaxToken closeBracketToken; + internal readonly InitializerExpressionSyntax initializer; + + internal ImplicitStackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 4; + this.AdjustFlagsAndWidth(stackAllocKeyword); + this.stackAllocKeyword = stackAllocKeyword; + this.AdjustFlagsAndWidth(openBracketToken); + this.openBracketToken = openBracketToken; + this.AdjustFlagsAndWidth(closeBracketToken); + this.closeBracketToken = closeBracketToken; + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } + + + internal ImplicitStackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 4; + this.AdjustFlagsAndWidth(stackAllocKeyword); + this.stackAllocKeyword = stackAllocKeyword; + this.AdjustFlagsAndWidth(openBracketToken); + this.openBracketToken = openBracketToken; + this.AdjustFlagsAndWidth(closeBracketToken); + this.closeBracketToken = closeBracketToken; + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } + + + internal ImplicitStackAllocArrayCreationExpressionSyntax(SyntaxKind kind, SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + : base(kind) + { + this.SlotCount = 4; + this.AdjustFlagsAndWidth(stackAllocKeyword); + this.stackAllocKeyword = stackAllocKeyword; + this.AdjustFlagsAndWidth(openBracketToken); + this.openBracketToken = openBracketToken; + this.AdjustFlagsAndWidth(closeBracketToken); + this.closeBracketToken = closeBracketToken; + this.AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } + + /// SyntaxToken representing the stackalloc keyword. + public SyntaxToken StackAllocKeyword { get { return this.stackAllocKeyword; } } + /// SyntaxToken representing the open bracket. + public SyntaxToken OpenBracketToken { get { return this.openBracketToken; } } + /// SyntaxToken representing the close bracket. + public SyntaxToken CloseBracketToken { get { return this.closeBracketToken; } } + /// InitializerExpressionSyntax representing the initializer expression of the implicit stackalloc array creation expression. + public InitializerExpressionSyntax Initializer { get { return this.initializer; } } + + internal override GreenNode GetSlot(int index) + { + switch (index) + { + case 0: return this.stackAllocKeyword; + case 1: return this.openBracketToken; + case 2: return this.closeBracketToken; + case 3: return this.initializer; + default: return null; + } + } + + internal override SyntaxNode CreateRed(SyntaxNode parent, int position) + { + return new CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax(this, parent, position); + } + + public override TResult Accept(CSharpSyntaxVisitor visitor) + { + return visitor.VisitImplicitStackAllocArrayCreationExpression(this); + } + + public override void Accept(CSharpSyntaxVisitor visitor) + { + visitor.VisitImplicitStackAllocArrayCreationExpression(this); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + { + if (stackAllocKeyword != this.StackAllocKeyword || openBracketToken != this.OpenBracketToken || closeBracketToken != this.CloseBracketToken || initializer != this.Initializer) + { + var newNode = SyntaxFactory.ImplicitStackAllocArrayCreationExpression(stackAllocKeyword, openBracketToken, closeBracketToken, initializer); + var diags = this.GetDiagnostics(); + if (diags != null && diags.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = this.GetAnnotations(); + if (annotations != null && annotations.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) + { + return new ImplicitStackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.openBracketToken, this.closeBracketToken, this.initializer, diagnostics, GetAnnotations()); + } + + internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) + { + return new ImplicitStackAllocArrayCreationExpressionSyntax(this.Kind, this.stackAllocKeyword, this.openBracketToken, this.closeBracketToken, this.initializer, GetDiagnostics(), annotations); + } + + internal ImplicitStackAllocArrayCreationExpressionSyntax(ObjectReader reader) + : base(reader) + { + this.SlotCount = 4; + var stackAllocKeyword = (SyntaxToken)reader.ReadValue(); + if (stackAllocKeyword != null) + { + AdjustFlagsAndWidth(stackAllocKeyword); + this.stackAllocKeyword = stackAllocKeyword; + } + var openBracketToken = (SyntaxToken)reader.ReadValue(); + if (openBracketToken != null) + { + AdjustFlagsAndWidth(openBracketToken); + this.openBracketToken = openBracketToken; + } + var closeBracketToken = (SyntaxToken)reader.ReadValue(); + if (closeBracketToken != null) + { + AdjustFlagsAndWidth(closeBracketToken); + this.closeBracketToken = closeBracketToken; + } + var initializer = (InitializerExpressionSyntax)reader.ReadValue(); + if (initializer != null) + { + AdjustFlagsAndWidth(initializer); + this.initializer = initializer; + } + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.stackAllocKeyword); + writer.WriteValue(this.openBracketToken); + writer.WriteValue(this.closeBracketToken); + writer.WriteValue(this.initializer); + } + + static ImplicitStackAllocArrayCreationExpressionSyntax() + { + ObjectBinder.RegisterTypeReader(typeof(ImplicitStackAllocArrayCreationExpressionSyntax), r => new ImplicitStackAllocArrayCreationExpressionSyntax(r)); + } + } + internal abstract partial class QueryClauseSyntax : CSharpSyntaxNode { internal QueryClauseSyntax(SyntaxKind kind, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) @@ -33893,6 +34080,11 @@ public virtual TResult VisitStackAllocArrayCreationExpression(StackAllocArrayCre return this.DefaultVisit(node); } + public virtual TResult VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + return this.DefaultVisit(node); + } + public virtual TResult VisitQueryExpression(QueryExpressionSyntax node) { return this.DefaultVisit(node); @@ -34917,6 +35109,11 @@ public virtual void VisitStackAllocArrayCreationExpression(StackAllocArrayCreati this.DefaultVisit(node); } + public virtual void VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + this.DefaultVisit(node); + } + public virtual void VisitQueryExpression(QueryExpressionSyntax node) { this.DefaultVisit(node); @@ -36092,7 +36289,17 @@ public override CSharpSyntaxNode VisitStackAllocArrayCreationExpression(StackAll { var stackAllocKeyword = (SyntaxToken)this.Visit(node.StackAllocKeyword); var type = (TypeSyntax)this.Visit(node.Type); - return node.Update(stackAllocKeyword, type); + var initializer = (InitializerExpressionSyntax)this.Visit(node.Initializer); + return node.Update(stackAllocKeyword, type, initializer); + } + + public override CSharpSyntaxNode VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + var stackAllocKeyword = (SyntaxToken)this.Visit(node.StackAllocKeyword); + var openBracketToken = (SyntaxToken)this.Visit(node.OpenBracketToken); + var closeBracketToken = (SyntaxToken)this.Visit(node.CloseBracketToken); + var initializer = (InitializerExpressionSyntax)this.Visit(node.Initializer); + return node.Update(stackAllocKeyword, openBracketToken, closeBracketToken, initializer); } public override CSharpSyntaxNode VisitQueryExpression(QueryExpressionSyntax node) @@ -39282,7 +39489,7 @@ public ImplicitArrayCreationExpressionSyntax ImplicitArrayCreationExpression(Syn return new ImplicitArrayCreationExpressionSyntax(SyntaxKind.ImplicitArrayCreationExpression, newKeyword, openBracketToken, commas.Node, closeBracketToken, initializer, this.context); } - public StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type) + public StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) { #if DEBUG if (stackAllocKeyword == null) @@ -39299,10 +39506,10 @@ public StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression #endif int hash; - var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, this.context, out hash); + var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, initializer, this.context, out hash); if (cached != null) return (StackAllocArrayCreationExpressionSyntax)cached; - var result = new StackAllocArrayCreationExpressionSyntax(SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, this.context); + var result = new StackAllocArrayCreationExpressionSyntax(SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, initializer, this.context); if (hash >= 0) { SyntaxNodeCache.AddNode(result, hash); @@ -39311,6 +39518,43 @@ public StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression return result; } + public ImplicitStackAllocArrayCreationExpressionSyntax ImplicitStackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + { +#if DEBUG + if (stackAllocKeyword == null) + throw new ArgumentNullException(nameof(stackAllocKeyword)); + switch (stackAllocKeyword.Kind) + { + case SyntaxKind.StackAllocKeyword: + break; + default: + throw new ArgumentException("stackAllocKeyword"); + } + if (openBracketToken == null) + throw new ArgumentNullException(nameof(openBracketToken)); + switch (openBracketToken.Kind) + { + case SyntaxKind.OpenBracketToken: + break; + default: + throw new ArgumentException("openBracketToken"); + } + if (closeBracketToken == null) + throw new ArgumentNullException(nameof(closeBracketToken)); + switch (closeBracketToken.Kind) + { + case SyntaxKind.CloseBracketToken: + break; + default: + throw new ArgumentException("closeBracketToken"); + } + if (initializer == null) + throw new ArgumentNullException(nameof(initializer)); +#endif + + return new ImplicitStackAllocArrayCreationExpressionSyntax(SyntaxKind.ImplicitStackAllocArrayCreationExpression, stackAllocKeyword, openBracketToken, closeBracketToken, initializer, this.context); + } + public QueryExpressionSyntax QueryExpression(FromClauseSyntax fromClause, QueryBodySyntax body) { #if DEBUG @@ -46208,7 +46452,7 @@ public static ImplicitArrayCreationExpressionSyntax ImplicitArrayCreationExpress return new ImplicitArrayCreationExpressionSyntax(SyntaxKind.ImplicitArrayCreationExpression, newKeyword, openBracketToken, commas.Node, closeBracketToken, initializer); } - public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type) + public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) { #if DEBUG if (stackAllocKeyword == null) @@ -46225,10 +46469,10 @@ public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExp #endif int hash; - var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, out hash); + var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, initializer, out hash); if (cached != null) return (StackAllocArrayCreationExpressionSyntax)cached; - var result = new StackAllocArrayCreationExpressionSyntax(SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type); + var result = new StackAllocArrayCreationExpressionSyntax(SyntaxKind.StackAllocArrayCreationExpression, stackAllocKeyword, type, initializer); if (hash >= 0) { SyntaxNodeCache.AddNode(result, hash); @@ -46237,6 +46481,43 @@ public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExp return result; } + public static ImplicitStackAllocArrayCreationExpressionSyntax ImplicitStackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + { +#if DEBUG + if (stackAllocKeyword == null) + throw new ArgumentNullException(nameof(stackAllocKeyword)); + switch (stackAllocKeyword.Kind) + { + case SyntaxKind.StackAllocKeyword: + break; + default: + throw new ArgumentException("stackAllocKeyword"); + } + if (openBracketToken == null) + throw new ArgumentNullException(nameof(openBracketToken)); + switch (openBracketToken.Kind) + { + case SyntaxKind.OpenBracketToken: + break; + default: + throw new ArgumentException("openBracketToken"); + } + if (closeBracketToken == null) + throw new ArgumentNullException(nameof(closeBracketToken)); + switch (closeBracketToken.Kind) + { + case SyntaxKind.CloseBracketToken: + break; + default: + throw new ArgumentException("closeBracketToken"); + } + if (initializer == null) + throw new ArgumentNullException(nameof(initializer)); +#endif + + return new ImplicitStackAllocArrayCreationExpressionSyntax(SyntaxKind.ImplicitStackAllocArrayCreationExpression, stackAllocKeyword, openBracketToken, closeBracketToken, initializer); + } + public static QueryExpressionSyntax QueryExpression(FromClauseSyntax fromClause, QueryBodySyntax body) { #if DEBUG @@ -51326,6 +51607,7 @@ internal static IEnumerable GetNodeTypes() typeof(ArrayCreationExpressionSyntax), typeof(ImplicitArrayCreationExpressionSyntax), typeof(StackAllocArrayCreationExpressionSyntax), + typeof(ImplicitStackAllocArrayCreationExpressionSyntax), typeof(QueryExpressionSyntax), typeof(QueryBodySyntax), typeof(FromClauseSyntax), diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs index 5d57fa01cf02f..926f6c6cc957e 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs @@ -352,6 +352,12 @@ public virtual TResult VisitStackAllocArrayCreationExpression(StackAllocArrayCre return this.DefaultVisit(node); } + /// Called when the visitor visits a ImplicitStackAllocArrayCreationExpressionSyntax node. + public virtual TResult VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + return this.DefaultVisit(node); + } + /// Called when the visitor visits a QueryExpressionSyntax node. public virtual TResult VisitQueryExpression(QueryExpressionSyntax node) { @@ -1579,6 +1585,12 @@ public virtual void VisitStackAllocArrayCreationExpression(StackAllocArrayCreati this.DefaultVisit(node); } + /// Called when the visitor visits a ImplicitStackAllocArrayCreationExpressionSyntax node. + public virtual void VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + this.DefaultVisit(node); + } + /// Called when the visitor visits a QueryExpressionSyntax node. public virtual void VisitQueryExpression(QueryExpressionSyntax node) { @@ -2902,7 +2914,17 @@ public override SyntaxNode VisitStackAllocArrayCreationExpression(StackAllocArra { var stackAllocKeyword = this.VisitToken(node.StackAllocKeyword); var type = (TypeSyntax)this.Visit(node.Type); - return node.Update(stackAllocKeyword, type); + var initializer = (InitializerExpressionSyntax)this.Visit(node.Initializer); + return node.Update(stackAllocKeyword, type, initializer); + } + + public override SyntaxNode VisitImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node) + { + var stackAllocKeyword = this.VisitToken(node.StackAllocKeyword); + var openBracketToken = this.VisitToken(node.OpenBracketToken); + var closeBracketToken = this.VisitToken(node.CloseBracketToken); + var initializer = (InitializerExpressionSyntax)this.Visit(node.Initializer); + return node.Update(stackAllocKeyword, openBracketToken, closeBracketToken, initializer); } public override SyntaxNode VisitQueryExpression(QueryExpressionSyntax node) @@ -5994,7 +6016,7 @@ public static ImplicitArrayCreationExpressionSyntax ImplicitArrayCreationExpress } /// Creates a new StackAllocArrayCreationExpressionSyntax instance. - public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type) + public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) { switch (stackAllocKeyword.Kind()) { @@ -6005,14 +6027,56 @@ public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExp } if (type == null) throw new ArgumentNullException(nameof(type)); - return (StackAllocArrayCreationExpressionSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.StackAllocArrayCreationExpression((Syntax.InternalSyntax.SyntaxToken)stackAllocKeyword.Node, type == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.TypeSyntax)type.Green).CreateRed(); + return (StackAllocArrayCreationExpressionSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.StackAllocArrayCreationExpression((Syntax.InternalSyntax.SyntaxToken)stackAllocKeyword.Node, type == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.TypeSyntax)type.Green, initializer == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.InitializerExpressionSyntax)initializer.Green).CreateRed(); } + /// Creates a new StackAllocArrayCreationExpressionSyntax instance. + public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(TypeSyntax type, InitializerExpressionSyntax initializer) + { + return SyntaxFactory.StackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), type, initializer); + } + /// Creates a new StackAllocArrayCreationExpressionSyntax instance. public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(TypeSyntax type) { - return SyntaxFactory.StackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), type); + return SyntaxFactory.StackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), type, default(InitializerExpressionSyntax)); + } + + /// Creates a new ImplicitStackAllocArrayCreationExpressionSyntax instance. + public static ImplicitStackAllocArrayCreationExpressionSyntax ImplicitStackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + { + switch (stackAllocKeyword.Kind()) + { + case SyntaxKind.StackAllocKeyword: + break; + default: + throw new ArgumentException("stackAllocKeyword"); + } + switch (openBracketToken.Kind()) + { + case SyntaxKind.OpenBracketToken: + break; + default: + throw new ArgumentException("openBracketToken"); + } + switch (closeBracketToken.Kind()) + { + case SyntaxKind.CloseBracketToken: + break; + default: + throw new ArgumentException("closeBracketToken"); + } + if (initializer == null) + throw new ArgumentNullException(nameof(initializer)); + return (ImplicitStackAllocArrayCreationExpressionSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.ImplicitStackAllocArrayCreationExpression((Syntax.InternalSyntax.SyntaxToken)stackAllocKeyword.Node, (Syntax.InternalSyntax.SyntaxToken)openBracketToken.Node, (Syntax.InternalSyntax.SyntaxToken)closeBracketToken.Node, initializer == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.InitializerExpressionSyntax)initializer.Green).CreateRed(); + } + + + /// Creates a new ImplicitStackAllocArrayCreationExpressionSyntax instance. + public static ImplicitStackAllocArrayCreationExpressionSyntax ImplicitStackAllocArrayCreationExpression(InitializerExpressionSyntax initializer) + { + return SyntaxFactory.ImplicitStackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), SyntaxFactory.Token(SyntaxKind.OpenBracketToken), SyntaxFactory.Token(SyntaxKind.CloseBracketToken), initializer); } /// Creates a new QueryExpressionSyntax instance. diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs index 9dcf7e032c4f9..106f7a6daa664 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs @@ -5081,6 +5081,7 @@ public ImplicitArrayCreationExpressionSyntax AddInitializerExpressions(params Ex public sealed partial class StackAllocArrayCreationExpressionSyntax : ExpressionSyntax { private TypeSyntax type; + private InitializerExpressionSyntax initializer; internal StackAllocArrayCreationExpressionSyntax(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.CSharpSyntaxNode green, SyntaxNode parent, int position) : base(green, parent, position) @@ -5102,11 +5103,21 @@ public TypeSyntax Type } } + /// InitializerExpressionSyntax node representing the initializer of the stackalloc array creation expression. + public InitializerExpressionSyntax Initializer + { + get + { + return this.GetRed(ref this.initializer, 2); + } + } + internal override SyntaxNode GetNodeSlot(int index) { switch (index) { case 1: return this.GetRed(ref this.type, 1); + case 2: return this.GetRed(ref this.initializer, 2); default: return null; } } @@ -5115,6 +5126,7 @@ internal override SyntaxNode GetCachedSlot(int index) switch (index) { case 1: return this.type; + case 2: return this.initializer; default: return null; } } @@ -5129,11 +5141,11 @@ public override void Accept(CSharpSyntaxVisitor visitor) visitor.VisitStackAllocArrayCreationExpression(this); } - public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, TypeSyntax type) + public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, TypeSyntax type, InitializerExpressionSyntax initializer) { - if (stackAllocKeyword != this.StackAllocKeyword || type != this.Type) + if (stackAllocKeyword != this.StackAllocKeyword || type != this.Type || initializer != this.Initializer) { - var newNode = SyntaxFactory.StackAllocArrayCreationExpression(stackAllocKeyword, type); + var newNode = SyntaxFactory.StackAllocArrayCreationExpression(stackAllocKeyword, type, initializer); var annotations = this.GetAnnotations(); if (annotations != null && annotations.Length > 0) return newNode.WithAnnotations(annotations); @@ -5145,12 +5157,121 @@ public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyw public StackAllocArrayCreationExpressionSyntax WithStackAllocKeyword(SyntaxToken stackAllocKeyword) { - return this.Update(stackAllocKeyword, this.Type); + return this.Update(stackAllocKeyword, this.Type, this.Initializer); } public StackAllocArrayCreationExpressionSyntax WithType(TypeSyntax type) { - return this.Update(this.StackAllocKeyword, type); + return this.Update(this.StackAllocKeyword, type, this.Initializer); + } + + public StackAllocArrayCreationExpressionSyntax WithInitializer(InitializerExpressionSyntax initializer) + { + return this.Update(this.StackAllocKeyword, this.Type, initializer); + } + } + + /// Class which represents the syntax node for implicit stackalloc array creation expression. + public sealed partial class ImplicitStackAllocArrayCreationExpressionSyntax : ExpressionSyntax + { + private InitializerExpressionSyntax initializer; + + internal ImplicitStackAllocArrayCreationExpressionSyntax(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.CSharpSyntaxNode green, SyntaxNode parent, int position) + : base(green, parent, position) + { + } + + /// SyntaxToken representing the stackalloc keyword. + public SyntaxToken StackAllocKeyword + { + get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.ImplicitStackAllocArrayCreationExpressionSyntax)this.Green).stackAllocKeyword, this.Position, 0); } + } + + /// SyntaxToken representing the open bracket. + public SyntaxToken OpenBracketToken + { + get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.ImplicitStackAllocArrayCreationExpressionSyntax)this.Green).openBracketToken, this.GetChildPosition(1), this.GetChildIndex(1)); } + } + + /// SyntaxToken representing the close bracket. + public SyntaxToken CloseBracketToken + { + get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.ImplicitStackAllocArrayCreationExpressionSyntax)this.Green).closeBracketToken, this.GetChildPosition(2), this.GetChildIndex(2)); } + } + + /// InitializerExpressionSyntax representing the initializer expression of the implicit stackalloc array creation expression. + public InitializerExpressionSyntax Initializer + { + get + { + return this.GetRed(ref this.initializer, 3); + } + } + + internal override SyntaxNode GetNodeSlot(int index) + { + switch (index) + { + case 3: return this.GetRed(ref this.initializer, 3); + default: return null; + } + } + internal override SyntaxNode GetCachedSlot(int index) + { + switch (index) + { + case 3: return this.initializer; + default: return null; + } + } + + public override TResult Accept(CSharpSyntaxVisitor visitor) + { + return visitor.VisitImplicitStackAllocArrayCreationExpression(this); + } + + public override void Accept(CSharpSyntaxVisitor visitor) + { + visitor.VisitImplicitStackAllocArrayCreationExpression(this); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, SyntaxToken openBracketToken, SyntaxToken closeBracketToken, InitializerExpressionSyntax initializer) + { + if (stackAllocKeyword != this.StackAllocKeyword || openBracketToken != this.OpenBracketToken || closeBracketToken != this.CloseBracketToken || initializer != this.Initializer) + { + var newNode = SyntaxFactory.ImplicitStackAllocArrayCreationExpression(stackAllocKeyword, openBracketToken, closeBracketToken, initializer); + var annotations = this.GetAnnotations(); + if (annotations != null && annotations.Length > 0) + return newNode.WithAnnotations(annotations); + return newNode; + } + + return this; + } + + public ImplicitStackAllocArrayCreationExpressionSyntax WithStackAllocKeyword(SyntaxToken stackAllocKeyword) + { + return this.Update(stackAllocKeyword, this.OpenBracketToken, this.CloseBracketToken, this.Initializer); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax WithOpenBracketToken(SyntaxToken openBracketToken) + { + return this.Update(this.StackAllocKeyword, openBracketToken, this.CloseBracketToken, this.Initializer); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax WithCloseBracketToken(SyntaxToken closeBracketToken) + { + return this.Update(this.StackAllocKeyword, this.OpenBracketToken, closeBracketToken, this.Initializer); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax WithInitializer(InitializerExpressionSyntax initializer) + { + return this.Update(this.StackAllocKeyword, this.OpenBracketToken, this.CloseBracketToken, initializer); + } + + public ImplicitStackAllocArrayCreationExpressionSyntax AddInitializerExpressions(params ExpressionSyntax[] items) + { + return this.WithInitializer(this.Initializer.WithExpressions(this.Initializer.Expressions.AddRange(items))); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs index a4f295d554120..61e5e87dd5b32 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs @@ -27,17 +27,23 @@ public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreat var elementType = stackAllocNode.ElementType; + var initializerOpt = stackAllocNode.InitializerOpt; + if (initializerOpt != null) + { + initializerOpt = initializerOpt.Update(VisitList(initializerOpt.Initializers)); + } + if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); - return new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type); + return new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, stackAllocNode.Type); } else if (type.OriginalDefinition == _compilation.GetWellKnownType(WellKnownType.System_Span_T)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var countTemp = _factory.StoreToTemp(rewrittenCount, out BoundAssignmentOperator countTempAssignment); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); - stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, spanType); + stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, spanType); var spanCtor = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor).SymbolAsMember(spanType); var ctorCall = _factory.New(spanCtor, stackAllocNode, countTemp); diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 7a7803df024bf..6043e070a35cb 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -10309,7 +10309,7 @@ private ExpressionSyntax ParseArrayOrObjectCreationExpression() { initializer = this.ParseArrayInitializer(); } - else if (type.Kind == SyntaxKind.ArrayType) + else { var rankSpec = ((ArrayTypeSyntax)type).RankSpecifiers[0]; if (GetNumberOfNonOmittedArraySizes(rankSpec) == 0) @@ -10585,10 +10585,11 @@ private void ParseExpressionsForComplexElementInitializer(ref SyntaxToken openBr } } } - + private bool IsImplicitlyTypedArray() { - return this.CurrentToken.Kind == SyntaxKind.NewKeyword && this.PeekToken(1).Kind == SyntaxKind.OpenBracketToken; + Debug.Assert(this.CurrentToken.Kind == SyntaxKind.NewKeyword || this.CurrentToken.Kind == SyntaxKind.StackAllocKeyword); + return this.PeekToken(1).Kind == SyntaxKind.OpenBracketToken; } private ImplicitArrayCreationExpressionSyntax ParseImplicitlyTypedArrayCreation() @@ -10685,11 +10686,48 @@ private PostSkipAction SkipBadArrayInitializerTokens(ref SyntaxToken openBrace, expected); } - private StackAllocArrayCreationExpressionSyntax ParseStackAllocExpression() + private ExpressionSyntax ParseStackAllocExpression() + { + if (this.IsImplicitlyTypedArray()) + { + return ParseImplicitlyTypedStackAllocExpression(); + } + else + { + return ParseRegularStackAllocExpression(); + } + } + + private ExpressionSyntax ParseImplicitlyTypedStackAllocExpression() { - var stackAlloc = this.EatToken(SyntaxKind.StackAllocKeyword); + var @stackalloc = this.EatToken(SyntaxKind.StackAllocKeyword); + @stackalloc = CheckFeatureAvailability(@stackalloc, MessageID.IDS_FeatureStackAllocInitializer); + var openBracket = this.EatToken(SyntaxKind.OpenBracketToken); + var closeBracket = this.EatToken(SyntaxKind.CloseBracketToken); + var initializer = this.ParseArrayInitializer(); + return _syntaxFactory.ImplicitStackAllocArrayCreationExpression(@stackalloc, openBracket, closeBracket, initializer); + } + + private ExpressionSyntax ParseRegularStackAllocExpression() + { + var @stackalloc = this.EatToken(SyntaxKind.StackAllocKeyword); var elementType = this.ParseType(expectSizes: true); - return _syntaxFactory.StackAllocArrayCreationExpression(stackAlloc, elementType); + InitializerExpressionSyntax initializer = null; + if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) + { + @stackalloc = CheckFeatureAvailability(@stackalloc, MessageID.IDS_FeatureStackAllocInitializer); + initializer = this.ParseArrayInitializer(); + } + else if (elementType.Kind == SyntaxKind.ArrayType) + { + var rankSpec = ((ArrayTypeSyntax)elementType).RankSpecifiers[0]; + if (GetNumberOfNonOmittedArraySizes(rankSpec) == 0) + { + elementType = this.AddError(elementType, rankSpec, ErrorCode.ERR_MissingArraySize); + } + } + + return _syntaxFactory.StackAllocArrayCreationExpression(@stackalloc, elementType, initializer); } private AnonymousMethodExpressionSyntax ParseAnonymousMethodExpression() diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index ac23b0502c300..4a0d7bfbb383a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -17,9 +17,27 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax.WithRefKindKeyword(Microsoft Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax.RefKindKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKindKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax.WithRefKindKeyword(Microsoft.CodeAnalysis.SyntaxToken refKindKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.AddInitializerExpressions(params Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.CloseBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.OpenBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.StackAllocKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken stackAllocKeyword, Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.WithCloseBracketToken(Microsoft.CodeAnalysis.SyntaxToken closeBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.WithInitializer(Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.WithOpenBracketToken(Microsoft.CodeAnalysis.SyntaxToken openBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.WithStackAllocKeyword(Microsoft.CodeAnalysis.SyntaxToken stackAllocKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.ReadOnlyKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithReadOnlyKeyword(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken stackAllocKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.WithInitializer(Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ImplicitStackAllocArrayCreationExpression = 9053 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode +override Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult static Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser.Script.get -> Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetConversion(this Microsoft.CodeAnalysis.Operations.IConversionOperation conversionExpression) -> Microsoft.CodeAnalysis.CSharp.Conversion static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Argument(Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax nameColon, Microsoft.CodeAnalysis.SyntaxToken refKindKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax @@ -28,4 +46,10 @@ static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeconstructionInfo(this static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeconstructionInfo(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax foreach) -> Microsoft.CodeAnalysis.CSharp.DeconstructionInfo static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInConversion(this Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation compoundAssignment) -> Microsoft.CodeAnalysis.CSharp.Conversion static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetOutConversion(this Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation compoundAssignment) -> Microsoft.CodeAnalysis.CSharp.Conversion -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CrefParameter(Microsoft.CodeAnalysis.SyntaxToken refKindKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax \ No newline at end of file +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.CrefParameter(Microsoft.CodeAnalysis.SyntaxToken refKindKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxToken stackAllocKeyword, Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxToken stackAllocKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitStackAllocArrayCreationExpressionSyntax node) -> TResult diff --git a/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs new file mode 100644 index 0000000000000..3882f81c59ba4 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp.Syntax +{ + public partial class StackAllocArrayCreationExpressionSyntax + { + public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyword, TypeSyntax type) + { + return Update(StackAllocKeyword, type, default(InitializerExpressionSyntax)); + } + } +} + +namespace Microsoft.CodeAnalysis.CSharp +{ + public partial class SyntaxFactory + { + public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExpression(SyntaxToken stackAllocKeyword, TypeSyntax type) + { + return StackAllocArrayCreationExpression(stackAllocKeyword, type, default(InitializerExpressionSyntax)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index b74cad86c874d..b6fcc66190ca2 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -1498,6 +1498,11 @@ TypeSyntax node representing the type of the stackalloc array. + + + InitializerExpressionSyntax node representing the initializer of the stackalloc array creation expression. + + Class which represents the syntax node for stackalloc array creation expression. @@ -1505,6 +1510,38 @@ Creates a StackAllocArrayCreationExpressionSyntax node. + + + + + + SyntaxToken representing the stackalloc keyword. + + + + + + SyntaxToken representing the open bracket. + + + + + + SyntaxToken representing the close bracket. + + + + + InitializerExpressionSyntax representing the initializer expression of the implicit stackalloc array creation expression. + + + + Class which represents the syntax node for implicit stackalloc array creation expression. + + + Creates an ImplicitStackAllocArrayCreationExpressionSyntax node. + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 34f006a9866a4..be5f0b8ad005f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -563,5 +563,7 @@ public enum SyntaxKind : ushort RefExpression = 9050, RefType = 9051, ThrowExpression = 9052, + + ImplicitStackAllocArrayCreationExpression = 9053, } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 295b41afcae2e..b589548dce920 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -8610,6 +8610,11 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f83a782a786fa..1dcb27e2caed8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -8610,6 +8610,11 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 8d4feb9eacc7e..5765b6ad8490a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -8610,6 +8610,11 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 4bd455eb0860a..dad97f8fed2f7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -8610,6 +8610,11 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 6b71e3ed4adcf..0448ebf73ddf4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -8610,6 +8610,11 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index b0ba89a18fde3..904a3e6402123 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -8610,6 +8610,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 5964ba1d21d98..873df201acb85 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -8610,6 +8610,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 3fa8d88eb9e3c..01f7c3621a3e7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -8610,6 +8610,11 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 8da7eec0a3595..7dd155d15d83d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -8610,6 +8610,11 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 395bfa09caa9e..8132882ecad60 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -8610,6 +8610,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index d0f8bdb24ce06..68bd6dd346d8f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -8610,6 +8610,11 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index a6567020b924a..a7a3e6b52c4b5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -8610,6 +8610,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 862c51a1a77e7..5d48d59a502e0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -8610,6 +8610,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref conditional expression + + stackalloc initializer + stackalloc initializer + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/StackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/StackAllocInitializerTests.cs new file mode 100644 index 0000000000000..344acb6d7a99c --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/StackAllocInitializerTests.cs @@ -0,0 +1,433 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + [CompilerTrait(CompilerFeature.StackAllocInitializer)] + public class StackAllocInitializerTests : CompilingTestBase + { + [Fact] + public void TestUnused() + { + var text = @" +using System; + +static unsafe class C +{ + static byte Method(int i) + { + Console.Write(i); + return 0; + } + + static void Main() + { + var p = stackalloc[] { 42, Method(1), 42, Method(2) }; + } +} +"; + CompileAndVerify(text, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), + options: TestOptions.UnsafeReleaseExe, + expectedOutput: "12", + verify: Verification.Passes).VerifyIL("C.Main", +@"{ + // Code size 19 (0x13) + .maxstack 1 + IL_0000: ldc.i4.s 16 + IL_0002: conv.u + IL_0003: pop + IL_0004: ldc.i4.1 + IL_0005: call ""byte C.Method(int)"" + IL_000a: pop + IL_000b: ldc.i4.2 + IL_000c: call ""byte C.Method(int)"" + IL_0011: pop + IL_0012: ret +}"); + } + + [Fact] + public void TestIdenticalBytes() + { + var text = @" +using System; + +static unsafe class C +{ + static void Print(byte* p) + { + for (int i = 0; i < 3; i++) + Console.Write(p[i]); + } + + static void Main() + { + byte* p = stackalloc byte[3] { 42, 42, 42 }; + Print(p); + } +} +"; + CompileAndVerify(text, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), + options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails, expectedOutput: @"424242").VerifyIL("C.Main", +@"{ + // Code size 16 (0x10) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: conv.u + IL_0002: localloc + IL_0004: dup + IL_0005: ldc.i4.s 42 + IL_0007: ldc.i4.3 + IL_0008: initblk + IL_000a: call ""void C.Print(byte*)"" + IL_000f: ret +}"); + } + + [Fact] + public void TestMixedBlockInit() + { + var text = @" +using System; + +static unsafe class C +{ + static void Print(byte* p) + { + for (int i = 0; i < 9; i++) + Console.Write(p[i]); + } + + static byte M() + { + return 9; + } + + static void Main() + { + byte* p = stackalloc byte[9] { 1, 2, 3, 4, 5, 6, 7, 8, M() }; + Print(p); + } +} +"; + CompileAndVerify(text, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), + options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails, expectedOutput: @"123456789").VerifyIL("C.Main", +@"{ + // Code size 30 (0x1e) + .maxstack 4 + IL_0000: ldc.i4.s 9 + IL_0002: conv.u + IL_0003: localloc + IL_0005: dup + IL_0006: ldsflda "".__StaticArrayInitTypeSize=9 .50BE2890A92A315C4BE0FA98C600C8939A260312"" + IL_000b: ldc.i4.s 9 + IL_000d: cpblk + IL_000f: dup + IL_0010: ldc.i4.8 + IL_0011: add + IL_0012: call ""byte C.M()"" + IL_0017: stind.i1 + IL_0018: call ""void C.Print(byte*)"" + IL_001d: ret +}"); + } + + [Fact] + public void TestElementInit() + { + var text = @" +using System; + +struct S +{ + public int i; +} + +static unsafe class C +{ + static void Print(S* p) + { + for (int i = 0; i < 3; i++) + Console.Write(p[i].i); + } + + static S M(int i) + { + return new S { i = i }; + } + + static void Main() + { + S* p = stackalloc S[3] { M(1), M(2), M(3) }; + Print(p); + } +} +"; + CompileAndVerify(text, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), + options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails ,expectedOutput: @"123").VerifyIL("C.Main", +@"{ + // Code size 70 (0x46) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: conv.u + IL_0002: sizeof ""S"" + IL_0008: mul.ovf.un + IL_0009: localloc + IL_000b: dup + IL_000c: ldc.i4.1 + IL_000d: call ""S C.M(int)"" + IL_0012: stobj ""S"" + IL_0017: dup + IL_0018: sizeof ""S"" + IL_001e: add + IL_001f: ldc.i4.2 + IL_0020: call ""S C.M(int)"" + IL_0025: stobj ""S"" + IL_002a: dup + IL_002b: ldc.i4.2 + IL_002c: conv.i + IL_002d: sizeof ""S"" + IL_0033: mul + IL_0034: add + IL_0035: ldc.i4.3 + IL_0036: call ""S C.M(int)"" + IL_003b: stobj ""S"" + IL_0040: call ""void C.Print(S*)"" + IL_0045: ret +}"); + } + + [Fact] + public void TestBytePointer() + { + Test("System.Byte", +@"{ + // Code size 19 (0x13) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: conv.u + IL_0002: localloc + IL_0004: dup + IL_0005: ldsflda "".__StaticArrayInitTypeSize=3 .7037807198C22A7D2B0807371D763779A84FDFCF"" + IL_000a: ldc.i4.3 + IL_000b: cpblk + IL_000d: call ""void C.Print(byte*)"" + IL_0012: ret +}"); + } + + [Fact] + public void TestInt32Pointer() + { + Test("System.Int32", +@"{ + // Code size 27 (0x1b) + .maxstack 4 + IL_0000: ldc.i4.s 12 + IL_0002: conv.u + IL_0003: localloc + IL_0005: dup + IL_0006: ldc.i4.1 + IL_0007: stind.i4 + IL_0008: dup + IL_0009: ldc.i4.4 + IL_000a: add + IL_000b: ldc.i4.2 + IL_000c: stind.i4 + IL_000d: dup + IL_000e: ldc.i4.2 + IL_000f: conv.i + IL_0010: ldc.i4.4 + IL_0011: mul + IL_0012: add + IL_0013: ldc.i4.3 + IL_0014: stind.i4 + IL_0015: call ""void C.Print(int*)"" + IL_001a: ret +}"); + } + + [Fact] + public void TestInt64Pointer() + { + Test("System.Int64", +@"{ + // Code size 30 (0x1e) + .maxstack 4 + IL_0000: ldc.i4.s 24 + IL_0002: conv.u + IL_0003: localloc + IL_0005: dup + IL_0006: ldc.i4.1 + IL_0007: conv.i8 + IL_0008: stind.i8 + IL_0009: dup + IL_000a: ldc.i4.8 + IL_000b: add + IL_000c: ldc.i4.2 + IL_000d: conv.i8 + IL_000e: stind.i8 + IL_000f: dup + IL_0010: ldc.i4.2 + IL_0011: conv.i + IL_0012: ldc.i4.8 + IL_0013: mul + IL_0014: add + IL_0015: ldc.i4.3 + IL_0016: conv.i8 + IL_0017: stind.i8 + IL_0018: call ""void C.Print(long*)"" + IL_001d: ret +}"); + } + + [Fact] + public void TestSpan() + { + var comp = CreateStandardCompilation(@" +using System; +static class C +{ + static void Main() + { + Span p = stackalloc byte[3] { 1, 2, 3 }; + } +} + +namespace System +{ + public ref struct Span { + public unsafe Span(void* p, int length) + { + for (int i = 0; i < 3; i++) + Console.Write(((byte*)p)[i]); + } + } +} +", options: TestOptions.UnsafeReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3)); + CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: @"123") + .VerifyIL("C.Main", +@"{ + // Code size 23 (0x17) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: conv.u + IL_0004: localloc + IL_0006: dup + IL_0007: ldsflda "".__StaticArrayInitTypeSize=3 .7037807198C22A7D2B0807371D763779A84FDFCF"" + IL_000c: ldc.i4.3 + IL_000d: cpblk + IL_000f: ldloc.0 + IL_0010: newobj ""System.Span..ctor(void*, int)"" + IL_0015: pop + IL_0016: ret +}"); + } + + [Fact] + public void TestReadOnlySpan() + { + var comp = CreateStandardCompilation(@" +using System; +static class C +{ + static void Main() + { + ReadOnlySpan p = stackalloc int[3] { 1, 2, 3 }; + } +} + +namespace System +{ + public ref struct Span + { + public unsafe Span(void* p, int length) + { + for (int i = 0; i < 3; i++) + Console.Write(((int*)p)[i]); + } + } + + public readonly ref struct ReadOnlySpan + { + public static implicit operator System.ReadOnlySpan (System.Span span) => default; + } +} +", options: TestOptions.UnsafeReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3)); + CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: @"123") + .VerifyIL("C.Main", +@"{ + // Code size 37 (0x25) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: conv.u + IL_0004: ldc.i4.4 + IL_0005: mul.ovf.un + IL_0006: localloc + IL_0008: dup + IL_0009: ldc.i4.1 + IL_000a: stind.i4 + IL_000b: dup + IL_000c: ldc.i4.4 + IL_000d: add + IL_000e: ldc.i4.2 + IL_000f: stind.i4 + IL_0010: dup + IL_0011: ldc.i4.2 + IL_0012: conv.i + IL_0013: ldc.i4.4 + IL_0014: mul + IL_0015: add + IL_0016: ldc.i4.3 + IL_0017: stind.i4 + IL_0018: ldloc.0 + IL_0019: newobj ""System.Span..ctor(void*, int)"" + IL_001e: call ""System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(System.Span)"" + IL_0023: pop + IL_0024: ret +}"); + } + + private static string GetSource(string pointerType) => $@" +using System; +using T = {pointerType}; +static unsafe class C +{{ + static void Print(T* p) + {{ + for (int i = 0; i < 3; i++) + Console.Write(p[i]); + }} + + static void Main() + {{ + T* p = stackalloc T[3] {{ 1, 2, 3 }}; + Print(p); + }} +}} +"; + + private void Test(string pointerType, string il) + => CompileAndVerify(GetSource(pointerType), + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), + options: TestOptions.UnsafeReleaseExe, + verify: Verification.Fails, + expectedOutput: @"123").VerifyIL("C.Main", il); + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs index 48ad6cc4cd9db..cb18000e24e4e 100644 --- a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs @@ -1150,6 +1150,32 @@ static void Main() Assert.Equal("y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } + [Fact] + public void TestStackAllocArrayInitializer() + { + var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" +class C { + static void Main() + { + int y = 1; + var x = stackalloc[] { +/**/ +y +/**/ + }; + } +} +"); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); + Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); + Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); + Assert.Equal("y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); + } + [WorkItem(539286, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539286")] [Fact] public void TestAnalysisInFieldInitializers() diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs new file mode 100644 index 0000000000000..e75a4ee5b6d80 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs @@ -0,0 +1,1622 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + [CompilerTrait(CompilerFeature.StackAllocInitializer)] + public class StackAllocInitializerTests : CompilingTestBase + { + [Fact] + public void NoBestType() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + struct A {} + struct B {} + + public void Method() + { + var p1 = stackalloc[] { new A(), new B() }; + var p2 = stackalloc[] { }; + var p3 = stackalloc[] { Method() }; + var p4 = stackalloc[] { null }; + var p5 = stackalloc[] { (1, null) }; + var p6 = stackalloc[] { () => { } }; + var p7 = stackalloc[] { new {} , new { i = 0 } }; + } +} +namespace System { + public struct ValueTuple { + public ValueTuple(T1 a, T2 b) { } + } +} +", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (9,18): error CS0826: No best type found for implicitly-typed array + // var p1 = stackalloc[] { new A(), new B() }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { new A(), new B() }").WithLocation(9, 18), + // (10,18): error CS0826: No best type found for implicitly-typed array + // var p2 = stackalloc[] { }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { }").WithLocation(10, 18), + // (11,18): error CS0826: No best type found for implicitly-typed array + // var p3 = stackalloc[] { Method() }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { Method() }").WithLocation(11, 18), + // (12,18): error CS0826: No best type found for implicitly-typed array + // var p4 = stackalloc[] { null }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { null }").WithLocation(12, 18), + // (13,18): error CS0826: No best type found for implicitly-typed array + // var p5 = stackalloc[] { (1, null) }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { (1, null) }").WithLocation(13, 18), + // (14,18): error CS0826: No best type found for implicitly-typed array + // var p6 = stackalloc[] { () => { } }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { () => { } }").WithLocation(14, 18), + // (15,18): error CS0826: No best type found for implicitly-typed array + // var p7 = stackalloc[] { new {} , new { i = 0 } }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "stackalloc[] { new {} , new { i = 0 } }").WithLocation(15, 18) + ); + } + + [Fact] + public void BestTypeNumeric() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc[] { 1, 1.2 }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var variables = tree.GetCompilationUnitRoot().DescendantNodes().OfType(); + Assert.Equal(1, variables.Count()); + + var obj1 = variables.ElementAt(0); + Assert.Equal("obj1", obj1.Identifier.Text); + + var obj1Value = model.GetSemanticInfoSummary(obj1.Initializer.Value); + Assert.Equal(SpecialType.System_Double, ((PointerTypeSymbol)obj1Value.Type).PointedAtType.SpecialType); + Assert.Equal(SpecialType.System_Double, ((PointerTypeSymbol)obj1Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.Identity, obj1Value.ImplicitConversion.Kind); + var declared = model.GetDeclaredSymbol(obj1.Initializer.Value); + Assert.Null(declared); + } + + [Fact] + public void BadBestType() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc[] { """" }; + var obj2 = stackalloc[] { new {} }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,20): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('string') + // var obj1 = stackalloc[] { "" }; + Diagnostic(ErrorCode.ERR_ManagedAddr, @"stackalloc[] { """" }").WithArguments("string").WithLocation(6, 20), + // (7,20): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('') + // var obj2 = stackalloc[] { new {} }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc[] { new {} }").WithArguments("").WithLocation(7, 20) + ); + } + + [Fact] + public void WrongLength() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc int[10] { }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,20): error CS0847: An array initializer of length '10' is expected + // var obj1 = stackalloc int[10] { }; + Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc int[10] { }").WithArguments("10").WithLocation(6, 20) + ); + } + + [Fact] + public void NoInit() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc int[]; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,34): error CS1586: Array creation must have array size or array initializer + // var obj1 = stackalloc int[]; + Diagnostic(ErrorCode.ERR_MissingArraySize, "[]").WithLocation(6, 34) + ); + } + + [Fact] + public void NestedInit() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc int[1] { { 42 } }; + var obj2 = stackalloc int[ ] { { 42 } }; + var obj3 = stackalloc [ ] { { 42 } }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,40): error CS0623: Array initializers can only be used in a variable or field initializer. Try using a new expression instead. + // var obj1 = stackalloc int[1] { { 42 } }; + Diagnostic(ErrorCode.ERR_ArrayInitInBadPlace, "{ 42 }").WithLocation(6, 40), + // (7,40): error CS0623: Array initializers can only be used in a variable or field initializer. Try using a new expression instead. + // var obj2 = stackalloc int[ ] { { 42 } }; + Diagnostic(ErrorCode.ERR_ArrayInitInBadPlace, "{ 42 }").WithLocation(7, 40), + // (8,40): error CS0623: Array initializers can only be used in a variable or field initializer. Try using a new expression instead. + // var obj3 = stackalloc [ ] { { 42 } }; + Diagnostic(ErrorCode.ERR_ArrayInitInBadPlace, "{ 42 }").WithLocation(8, 40) + ); + } + + [Fact] + public void AsStatement() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + stackalloc[] {1}; + stackalloc int[] {1}; + stackalloc int[1] {1}; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,9): error CS1525: Invalid expression term 'stackalloc' + // stackalloc[] {1}; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 9), + // (6,9): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // stackalloc[] {1}; + Diagnostic(ErrorCode.ERR_IllegalStatement, "stackalloc[] {1}").WithLocation(6, 9), + // (7,9): error CS1525: Invalid expression term 'stackalloc' + // stackalloc int[] {1}; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 9), + // (7,9): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // stackalloc int[] {1}; + Diagnostic(ErrorCode.ERR_IllegalStatement, "stackalloc int[] {1}").WithLocation(7, 9), + // (8,9): error CS1525: Invalid expression term 'stackalloc' + // stackalloc int[1] {1}; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 9), + // (8,9): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // stackalloc int[1] {1}; + Diagnostic(ErrorCode.ERR_IllegalStatement, "stackalloc int[1] {1}").WithLocation(8, 9) + ); + } + + [Fact] + public void BadRank() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc int[][] { 1 }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,31): error CS1575: A stackalloc expression requires [] after type + // var obj1 = stackalloc int[][] { 1 }; + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[][]").WithLocation(6, 31) + ); + } + + [Fact] + public void BadDimension() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public void Method1() + { + var obj1 = stackalloc int[,] { 1 }; + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (6,31): error CS1575: A stackalloc expression requires [] after type + // var obj1 = stackalloc int[,] { 1 }; + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[,]").WithLocation(6, 31) + ); + } + + [Fact] + public void TestFlowPass1() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +using System; +unsafe class Test +{ + public static void Main() + { + int i, j, k; + var obj1 = stackalloc int [1] { i = 1 }; + var obj2 = stackalloc int [ ] { j = 2 }; + var obj3 = stackalloc [ ] { k = 3 }; + + Console.Write(i); + Console.Write(j); + Console.Write(k); + } +}", TestOptions.UnsafeReleaseExe); + + CompileAndVerify(comp, expectedOutput: "123"); + } + + [Fact] + public void TestFlowPass2() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +unsafe class Test +{ + public static void Main() + { + int i, j, k; + var obj1 = stackalloc int [1] { i }; + var obj2 = stackalloc int [ ] { j }; + var obj3 = stackalloc [ ] { k }; + } +}", TestOptions.UnsafeReleaseExe); + + comp.VerifyDiagnostics( + // (7,41): error CS0165: Use of unassigned local variable 'i' + // var obj1 = stackalloc int [1] { i }; + Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(7, 41), + // (8,41): error CS0165: Use of unassigned local variable 'j' + // var obj2 = stackalloc int [ ] { j }; + Diagnostic(ErrorCode.ERR_UseDefViolation, "j").WithArguments("j").WithLocation(8, 41), + // (9,41): error CS0165: Use of unassigned local variable 'k' + // var obj3 = stackalloc [ ] { k }; + Diagnostic(ErrorCode.ERR_UseDefViolation, "k").WithArguments("k").WithLocation(9, 41) + ); + } + + [Fact] + public void ConversionFromPointerStackAlloc_UserDefined_Implicit() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +using System; +unsafe class Test +{ + public void Method1() + { + Test obj1 = stackalloc int[3] { 1, 2, 3 }; + var obj2 = stackalloc int[3] { 1, 2, 3 }; + Span obj3 = stackalloc int[3] { 1, 2, 3 }; + int* obj4 = stackalloc int[3] { 1, 2, 3 }; + double* obj5 = stackalloc int[3] { 1, 2, 3 }; + } + + public void Method2() + { + Test obj1 = stackalloc int[] { 1, 2, 3 }; + var obj2 = stackalloc int[] { 1, 2, 3 }; + Span obj3 = stackalloc int[] { 1, 2, 3 }; + int* obj4 = stackalloc int[] { 1, 2, 3 }; + double* obj5 = stackalloc int[] { 1, 2, 3 }; + } + + public void Method3() + { + Test obj1 = stackalloc[] { 1, 2, 3 }; + var obj2 = stackalloc[] { 1, 2, 3 }; + Span obj3 = stackalloc[] { 1, 2, 3 }; + int* obj4 = stackalloc[] { 1, 2, 3 }; + double* obj5 = stackalloc[] { 1, 2, 3 }; + } + + public static implicit operator Test(int* value) + { + return default(Test); + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (11,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc int[3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[3] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(11, 24), + // (20,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc int[] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(20, 24), + // (29,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc[] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc[] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(29, 24) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var variables = tree.GetCompilationUnitRoot().DescendantNodes().OfType(); + Assert.Equal(15, variables.Count()); + + for (int i = 0; i < 15; i += 5) + { + var obj1 = variables.ElementAt(i); + Assert.Equal("obj1", obj1.Identifier.Text); + + var obj1Value = model.GetSemanticInfoSummary(obj1.Initializer.Value); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj1Value.Type).PointedAtType.SpecialType); + Assert.Equal("Test", obj1Value.ConvertedType.Name); + Assert.Equal(ConversionKind.ImplicitUserDefined, obj1Value.ImplicitConversion.Kind); + + var obj2 = variables.ElementAt(i + 1); + Assert.Equal("obj2", obj2.Identifier.Text); + + var obj2Value = model.GetSemanticInfoSummary(obj2.Initializer.Value); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj2Value.Type).PointedAtType.SpecialType); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj2Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.Identity, obj2Value.ImplicitConversion.Kind); + + var obj3 = variables.ElementAt(i + 2); + Assert.Equal("obj3", obj3.Identifier.Text); + + var obj3Value = model.GetSemanticInfoSummary(obj3.Initializer.Value); + Assert.Equal("Span", obj3Value.Type.Name); + Assert.Equal("Span", obj3Value.ConvertedType.Name); + Assert.Equal(ConversionKind.Identity, obj3Value.ImplicitConversion.Kind); + + var obj4 = variables.ElementAt(i + 3); + Assert.Equal("obj4", obj4.Identifier.Text); + + var obj4Value = model.GetSemanticInfoSummary(obj4.Initializer.Value); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj4Value.Type).PointedAtType.SpecialType); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj4Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.Identity, obj4Value.ImplicitConversion.Kind); + + var obj5 = variables.ElementAt(i + 4); + Assert.Equal("obj5", obj5.Identifier.Text); + + var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value); + Assert.Null(obj5Value.Type); + Assert.Equal(SpecialType.System_Double, ((PointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind); + } + } + + [Fact] + public void ConversionFromPointerStackAlloc_UserDefined_Explicit() + { + var comp = CreateCompilationWithMscorlibAndSpan(@" +using System; +unsafe class Test +{ + public void Method1() + { + Test obj1 = (Test)stackalloc int[3] { 1, 2, 3 }; + var obj2 = stackalloc int[3] { 1, 2, 3 }; + Span obj3 = stackalloc int[3] { 1, 2, 3 }; + int* obj4 = stackalloc int[3] { 1, 2, 3 }; + double* obj5 = stackalloc int[3] { 1, 2, 3 }; + } + + public void Method2() + { + Test obj1 = (Test)stackalloc int[] { 1, 2, 3 }; + var obj2 = stackalloc int[] { 1, 2, 3 }; + Span obj3 = stackalloc int[] { 1, 2, 3 }; + int* obj4 = stackalloc int[] { 1, 2, 3 }; + double* obj5 = stackalloc int[] { 1, 2, 3 }; + } + + public void Method3() + { + Test obj1 = (Test)stackalloc [] { 1, 2, 3 }; + var obj2 = stackalloc[] { 1, 2, 3 }; + Span obj3 = stackalloc [] { 1, 2, 3 }; + int* obj4 = stackalloc[] { 1, 2, 3 }; + double* obj5 = stackalloc[] { 1, 2, 3 }; + } + + public static explicit operator Test(Span value) + { + return default(Test); + } +}", TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (11,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc int[3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[3] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(11, 24), + // (20,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc int[] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(20, 24), + // (29,24): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double*' is not possible. + // double* obj5 = stackalloc[] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc[] { 1, 2, 3 }").WithArguments("int", "double*").WithLocation(29, 24) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var variables = tree.GetCompilationUnitRoot().DescendantNodes().OfType(); + Assert.Equal(15, variables.Count()); + + for (int i = 0; i < 15; i += 5) + { + var obj1 = variables.ElementAt(i); + Assert.Equal("obj1", obj1.Identifier.Text); + Assert.Equal(SyntaxKind.CastExpression, obj1.Initializer.Value.Kind()); + + var obj1Value = model.GetSemanticInfoSummary(((CastExpressionSyntax)obj1.Initializer.Value).Expression); + Assert.Equal("Span", obj1Value.Type.Name); + Assert.Equal("Span", obj1Value.ConvertedType.Name); + Assert.Equal(ConversionKind.Identity, obj1Value.ImplicitConversion.Kind); + + var obj2 = variables.ElementAt(i + 1); + Assert.Equal("obj2", obj2.Identifier.Text); + + var obj2Value = model.GetSemanticInfoSummary(obj2.Initializer.Value); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj2Value.Type).PointedAtType.SpecialType); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj2Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.Identity, obj2Value.ImplicitConversion.Kind); + + var obj3 = variables.ElementAt(i + 2); + Assert.Equal("obj3", obj3.Identifier.Text); + + var obj3Value = model.GetSemanticInfoSummary(obj3.Initializer.Value); + Assert.Equal("Span", obj3Value.Type.Name); + Assert.Equal("Span", obj3Value.ConvertedType.Name); + Assert.Equal(ConversionKind.Identity, obj3Value.ImplicitConversion.Kind); + + var obj4 = variables.ElementAt(i + 3); + Assert.Equal("obj4", obj4.Identifier.Text); + + var obj4Value = model.GetSemanticInfoSummary(obj4.Initializer.Value); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj4Value.Type).PointedAtType.SpecialType); + Assert.Equal(SpecialType.System_Int32, ((PointerTypeSymbol)obj4Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.Identity, obj4Value.ImplicitConversion.Kind); + + var obj5 = variables.ElementAt(i + 4); + Assert.Equal("obj5", obj5.Identifier.Text); + + var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value); + Assert.Null(obj5Value.Type); + Assert.Equal(SpecialType.System_Double, ((PointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType); + Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind); + } + } + + [Fact] + public void ConversionError() + { + CreateCompilationWithMscorlibAndSpan(@" +class Test +{ + void Method1() + { + double x = stackalloc int[3] { 1, 2, 3 }; // implicit + short y = (short)stackalloc int[3] { 1, 2, 3 }; // explicit + } + + void Method2() + { + double x = stackalloc int[] { 1, 2, 3 }; // implicit + short y = (short)stackalloc int[] { 1, 2, 3 }; // explicit + } + + void Method3() + { + double x = stackalloc[] { 1, 2, 3 }; // implicit + short y = (short)stackalloc[] { 1, 2, 3 }; // explicit + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + + // (6,20): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double' is not possible. + // double x = stackalloc int[3] { 1, 2, 3 }; // implicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[3] { 1, 2, 3 }").WithArguments("int", "double").WithLocation(6, 20), + // (7,19): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'short' is not possible. + // short y = (short)stackalloc int[3] { 1, 2, 3 }; // explicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(short)stackalloc int[3] { 1, 2, 3 }").WithArguments("int", "short").WithLocation(7, 19), + // (12,20): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double' is not possible. + // double x = stackalloc int[] { 1, 2, 3 }; // implicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[] { 1, 2, 3 }").WithArguments("int", "double").WithLocation(12, 20), + // (13,19): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'short' is not possible. + // short y = (short)stackalloc int[] { 1, 2, 3 }; // explicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(short)stackalloc int[] { 1, 2, 3 }").WithArguments("int", "short").WithLocation(13, 19), + // (18,20): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'double' is not possible. + // double x = stackalloc[] { 1, 2, 3 }; // implicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc[] { 1, 2, 3 }").WithArguments("int", "double").WithLocation(18, 20), + // (19,19): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'short' is not possible. + // short y = (short)stackalloc[] { 1, 2, 3 }; // explicit + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(short)stackalloc[] { 1, 2, 3 }").WithArguments("int", "short").WithLocation(19, 19) + ); + } + + [Fact] + public void MissingSpanType() + { + CreateStandardCompilation(@" +class Test +{ + void M() + { + Span a1 = stackalloc int [3] { 1, 2, 3 }; + Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Span a3 = stackalloc [ ] { 1, 2, 3 }; + } +}").VerifyDiagnostics( + // (6,9): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?) + // Span a1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Span").WithArguments("Span<>").WithLocation(6, 9), + // (6,24): error CS0518: Predefined type 'System.Span`1' is not defined or imported + // Span a1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int [3] { 1, 2, 3 }").WithArguments("System.Span`1").WithLocation(6, 24), + // (7,9): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?) + // Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Span").WithArguments("Span<>").WithLocation(7, 9), + // (7,24): error CS0518: Predefined type 'System.Span`1' is not defined or imported + // Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int [ ] { 1, 2, 3 }").WithArguments("System.Span`1").WithLocation(7, 24), + // (8,9): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?) + // Span a3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Span").WithArguments("Span<>").WithLocation(8, 9), + // (8,24): error CS0518: Predefined type 'System.Span`1' is not defined or imported + // Span a3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc [ ] { 1, 2, 3 }").WithArguments("System.Span`1").WithLocation(8, 24) + ); + } + + [Fact] + public void MissingSpanConstructor() + { + CreateStandardCompilation(@" +namespace System +{ + ref struct Span + { + } + class Test + { + void M() + { + Span a1 = stackalloc int [3] { 1, 2, 3 }; + Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Span a3 = stackalloc [ ] { 1, 2, 3 }; + } + } +}").VerifyDiagnostics( + // (11,28): error CS0656: Missing compiler required member 'System.Span`1..ctor' + // Span a1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "stackalloc int [3] { 1, 2, 3 }").WithArguments("System.Span`1", ".ctor").WithLocation(11, 28), + // (12,28): error CS0656: Missing compiler required member 'System.Span`1..ctor' + // Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "stackalloc int [ ] { 1, 2, 3 }").WithArguments("System.Span`1", ".ctor").WithLocation(12, 28), + // (13,28): error CS0656: Missing compiler required member 'System.Span`1..ctor' + // Span a3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "stackalloc [ ] { 1, 2, 3 }").WithArguments("System.Span`1", ".ctor").WithLocation(13, 28) + ); + } + + [Fact] + public void ConditionalExpressionOnSpan_BothStackallocSpans() + { + CreateCompilationWithMscorlibAndSpan(@" +class Test +{ + void M() + { + var x1 = true ? stackalloc int [3] { 1, 2, 3 } : stackalloc int [3] { 1, 2, 3 }; + var x2 = true ? stackalloc int [ ] { 1, 2, 3 } : stackalloc int [ ] { 1, 2, 3 }; + var x3 = true ? stackalloc [ ] { 1, 2, 3 } : stackalloc [ ] { 1, 2, 3 }; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void ConditionalExpressionOnSpan_Convertible() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + void M() + { + var x1 = true ? stackalloc int [3] { 1, 2, 3 } : (Span)stackalloc int [3] { 1, 2, 3 }; + var x2 = true ? stackalloc int [ ] { 1, 2, 3 } : (Span)stackalloc int [ ] { 1, 2, 3 }; + var x3 = true ? stackalloc [ ] { 1, 2, 3 } : (Span)stackalloc [ ] { 1, 2, 3 }; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void ConditionalExpressionOnSpan_NoCast() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + void M() + { + var x1 = true ? stackalloc int [3] { 1, 2, 3, } : (Span)stackalloc short [3] { (short)1, (short)2, (short)3 }; + var x2 = true ? stackalloc int [ ] { 1, 2, 3, } : (Span)stackalloc short [ ] { (short)1, (short)2, (short)3 }; + var x3 = true ? stackalloc [ ] { 1, 2, 3, } : (Span)stackalloc [ ] { (short)1, (short)2, (short)3 }; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,59): error CS8346: Conversion of a stackalloc expression of type 'short' to type 'Span' is not possible. + // var x1 = true ? stackalloc int [3] { 1, 2, 3, } : (Span)stackalloc short [3] { (short)1, (short)2, (short)3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(Span)stackalloc short [3] { (short)1, (short)2, (short)3 }").WithArguments("short", "System.Span").WithLocation(7, 59), + // (8,59): error CS8346: Conversion of a stackalloc expression of type 'short' to type 'Span' is not possible. + // var x2 = true ? stackalloc int [ ] { 1, 2, 3, } : (Span)stackalloc short [ ] { (short)1, (short)2, (short)3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(Span)stackalloc short [ ] { (short)1, (short)2, (short)3 }").WithArguments("short", "System.Span").WithLocation(8, 59), + // (9,59): error CS8346: Conversion of a stackalloc expression of type 'short' to type 'Span' is not possible. + // var x3 = true ? stackalloc [ ] { 1, 2, 3, } : (Span)stackalloc [ ] { (short)1, (short)2, (short)3 }; + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(Span)stackalloc [ ] { (short)1, (short)2, (short)3 }").WithArguments("short", "System.Span").WithLocation(9, 59) + ); + } + + [Fact] + public void ConditionalExpressionOnSpan_CompatibleTypes() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + void M() + { + Span a1 = stackalloc int [3] { 1, 2, 3 }; + Span a2 = stackalloc int [ ] { 1, 2, 3 }; + Span a3 = stackalloc [ ] { 1, 2, 3 }; + + var x1 = true ? stackalloc int [3] { 1, 2, 3 } : a1; + var x2 = true ? stackalloc int [ ] { 1, 2, 3 } : a2; + var x3 = true ? stackalloc [ ] { 1, 2, 3 } : a3; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void ConditionalExpressionOnSpan_IncompatibleTypes() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + void M() + { + Span a = stackalloc short [10]; + var x1 = true ? stackalloc int [3] { 1, 2, 3 } : a; + var x2 = true ? stackalloc int [ ] { 1, 2, 3 } : a; + var x3 = true ? stackalloc [ ] { 1, 2, 3 } : a; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'stackalloc int[3]' and 'Span' + // var x1 = true ? stackalloc int [3] { 1, 2, 3 } : a; + Diagnostic(ErrorCode.ERR_InvalidQM, "true ? stackalloc int [3] { 1, 2, 3 } : a").WithArguments("stackalloc int[3]", "System.Span").WithLocation(8, 18), + // (9,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'stackalloc int[]' and 'Span' + // var x2 = true ? stackalloc int [ ] { 1, 2, 3 } : a; + Diagnostic(ErrorCode.ERR_InvalidQM, "true ? stackalloc int [ ] { 1, 2, 3 } : a").WithArguments("stackalloc int[]", "System.Span").WithLocation(9, 18), + // (10,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'stackalloc int[]' and 'Span' + // var x3 = true ? stackalloc [ ] { 1, 2, 3 } : a; + Diagnostic(ErrorCode.ERR_InvalidQM, "true ? stackalloc [ ] { 1, 2, 3 } : a").WithArguments("stackalloc int[]", "System.Span").WithLocation(10, 18) + ); + } + + [Fact] + public void ConditionalExpressionOnSpan_Nested() + { + CreateCompilationWithMscorlibAndSpan(@" +class Test +{ + bool N() => true; + + void M() + { + var x = N() + ? N() + ? stackalloc int[1] { 42 } + : stackalloc int[ ] { 42 } + : N() + ? stackalloc[] { 42 } + : N() + ? stackalloc int[2] + : stackalloc int[3]; + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void BooleanOperatorOnSpan_NoTargetTyping() + { + CreateCompilationWithMscorlibAndSpan(@" +class Test +{ + void M() + { + if (stackalloc int[3] { 1, 2, 3 } == stackalloc int[3] { 1, 2, 3 }) { } + if (stackalloc int[ ] { 1, 2, 3 } == stackalloc int[ ] { 1, 2, 3 }) { } + if (stackalloc [ ] { 1, 2, 3 } == stackalloc [ ] { 1, 2, 3 }) { } + } +}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,13): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc int[3] { 1, 2, 3 } == stackalloc int[3] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 13), + // (6,46): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc int[3] { 1, 2, 3 } == stackalloc int[3] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 46), + // (7,13): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc int[ ] { 1, 2, 3 } == stackalloc int[ ] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 13), + // (7,46): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc int[ ] { 1, 2, 3 } == stackalloc int[ ] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 46), + // (8,13): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc [ ] { 1, 2, 3 } == stackalloc [ ] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 13), + // (8,46): error CS1525: Invalid expression term 'stackalloc' + // if (stackalloc [ ] { 1, 2, 3 } == stackalloc [ ] { 1, 2, 3 }) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 46) + ); + } + + [Fact] + public void StackAllocInitializerSyntaxProducesErrorsOnEarlierVersions() + { + var parseOptions = new CSharpParseOptions().WithLanguageVersion(LanguageVersion.CSharp7); + + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + void M() + { + Span x1 = stackalloc int [3] { 1, 2, 3 }; + Span x2 = stackalloc int [ ] { 1, 2, 3 }; + Span x3 = stackalloc [ ] { 1, 2, 3 }; + } +}", options: TestOptions.UnsafeReleaseDll, parseOptions: parseOptions).VerifyDiagnostics( + // (7,24): error CS8107: Feature 'stackalloc initilizer' is not available in C# 7.0. Please use language version 7.3 or greater. + // Span x1 = stackalloc int[1] { 2 }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(7, 24), + // (8,24): error CS8107: Feature 'stackalloc initilizer' is not available in C# 7.0. Please use language version 7.3 or greater. + // Span x2 = stackalloc int[] { 2 }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(8, 24), + // (9,24): error CS8107: Feature 'stackalloc initilizer' is not available in C# 7.0. Please use language version 7.3 or greater. + // Span x3 = stackalloc [] { 2 }; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(9, 24) + ); + } + + [Fact] + public void StackAllocSyntaxProducesUnsafeErrorInSafeCode() + { + CreateStandardCompilation(@" +class Test +{ + void M() + { + var x1 = stackalloc int [3] { 1, 2, 3 }; + var x2 = stackalloc int [ ] { 1, 2, 3 }; + var x3 = stackalloc [ ] { 1, 2, 3 }; + } +}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var x1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int [3] { 1, 2, 3 }").WithLocation(6, 18), + // (7,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var x2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(7, 18), + // (8,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var x3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc [ ] { 1, 2, 3 }").WithLocation(8, 18) + ); + } + + [Fact] + public void StackAllocInUsing1() + { + var test = @" +public class Test +{ + unsafe public static void Main() + { + using (var v1 = stackalloc int [3] { 1, 2, 3 }) + using (var v2 = stackalloc int [ ] { 1, 2, 3 }) + using (var v3 = stackalloc [ ] { 1, 2, 3 }) + { + } + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (6,16): error CS1674: 'int*': type used in a using statement must be implicitly convertible to 'System.IDisposable' + // using (var v1 = stackalloc int [3] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_NoConvToIDisp, "var v1 = stackalloc int [3] { 1, 2, 3 }").WithArguments("int*").WithLocation(6, 16), + // (7,16): error CS1674: 'int*': type used in a using statement must be implicitly convertible to 'System.IDisposable' + // using (var v2 = stackalloc int [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_NoConvToIDisp, "var v2 = stackalloc int [ ] { 1, 2, 3 }").WithArguments("int*").WithLocation(7, 16), + // (8,16): error CS1674: 'int*': type used in a using statement must be implicitly convertible to 'System.IDisposable' + // using (var v3 = stackalloc [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_NoConvToIDisp, "var v3 = stackalloc [ ] { 1, 2, 3 }").WithArguments("int*").WithLocation(8, 16) + ); + } + + [Fact] + public void StackAllocInUsing2() + { + var test = @" +public class Test +{ + unsafe public static void Main() + { + using (System.IDisposable v1 = stackalloc int [3] { 1, 2, 3 }) + using (System.IDisposable v2 = stackalloc int [ ] { 1, 2, 3 }) + using (System.IDisposable v3 = stackalloc [ ] { 1, 2, 3 }) + { + } + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (6,40): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'IDisposable' is not possible. + // using (System.IDisposable v1 = stackalloc int [3] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int [3] { 1, 2, 3 }").WithArguments("int", "System.IDisposable").WithLocation(6, 40), + // (7,40): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'IDisposable' is not possible. + // using (System.IDisposable v2 = stackalloc int [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int [ ] { 1, 2, 3 }").WithArguments("int", "System.IDisposable").WithLocation(7, 40), + // (8,40): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'IDisposable' is not possible. + // using (System.IDisposable v3 = stackalloc [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc [ ] { 1, 2, 3 }").WithArguments("int", "System.IDisposable").WithLocation(8, 40) + ); + } + + [Fact] + public void StackAllocInFixed() + { + var test = @" +public class Test +{ + unsafe public static void Main() + { + fixed (int* v1 = stackalloc int [3] { 1, 2, 3 }) + fixed (int* v2 = stackalloc int [ ] { 1, 2, 3 }) + fixed (int* v3 = stackalloc [ ] { 1, 2, 3 }) + { + } + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (6,26): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression + // fixed (int* v1 = stackalloc int [3] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_FixedNotNeeded, "stackalloc int [3] { 1, 2, 3 }").WithLocation(6, 26), + // (7,26): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression + // fixed (int* v2 = stackalloc int [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_FixedNotNeeded, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(7, 26), + // (8,26): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression + // fixed (int* v3 = stackalloc [ ] { 1, 2, 3 }) + Diagnostic(ErrorCode.ERR_FixedNotNeeded, "stackalloc [ ] { 1, 2, 3 }").WithLocation(8, 26) + ); + } + + [Fact] + public void ConstStackAllocExpression() + { + var test = @" +unsafe public class Test +{ + void M() + { + const int* p1 = stackalloc int [3] { 1, 2, 3 }; + const int* p2 = stackalloc int [ ] { 1, 2, 3 }; + const int* p3 = stackalloc [ ] { 1, 2, 3 }; + } +} +"; + CreateStandardCompilation(test, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)).VerifyDiagnostics( + // (6,15): error CS0283: The type 'int*' cannot be declared const + // const int* p1 = stackalloc int[1] { 1 }; + Diagnostic(ErrorCode.ERR_BadConstType, "int*").WithArguments("int*").WithLocation(6, 15), + // (7,15): error CS0283: The type 'int*' cannot be declared const + // const int* p2 = stackalloc int[] { 1 }; + Diagnostic(ErrorCode.ERR_BadConstType, "int*").WithArguments("int*").WithLocation(7, 15), + // (8,15): error CS0283: The type 'int*' cannot be declared const + // const int* p3 = stackalloc [] { 1 }; + Diagnostic(ErrorCode.ERR_BadConstType, "int*").WithArguments("int*").WithLocation(8, 15) + ); + } + + [Fact] + public void RefStackAllocAssignment_ValueToRef() + { + var test = @" +using System; +public class Test +{ + void M() + { + ref Span p1 = stackalloc int [3] { 1, 2, 3 }; + ref Span p2 = stackalloc int [ ] { 1, 2, 3 }; + ref Span p3 = stackalloc [ ] { 1, 2, 3 }; + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (7,23): error CS8172: Cannot initialize a by-reference variable with a value + // ref Span p1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "p1 = stackalloc int [3] { 1, 2, 3 }").WithLocation(7, 23), + // (7,28): error CS1510: A ref or out value must be an assignable variable + // ref Span p1 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "stackalloc int [3] { 1, 2, 3 }").WithLocation(7, 28), + // (8,23): error CS8172: Cannot initialize a by-reference variable with a value + // ref Span p2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "p2 = stackalloc int [ ] { 1, 2, 3 }").WithLocation(8, 23), + // (8,28): error CS1510: A ref or out value must be an assignable variable + // ref Span p2 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(8, 28), + // (9,23): error CS8172: Cannot initialize a by-reference variable with a value + // ref Span p3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "p3 = stackalloc [ ] { 1, 2, 3 }").WithLocation(9, 23), + // (9,28): error CS1510: A ref or out value must be an assignable variable + // ref Span p3 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "stackalloc [ ] { 1, 2, 3 }").WithLocation(9, 28) + ); + } + + [Fact] + public void RefStackAllocAssignment_RefToRef() + { + var test = @" +using System; +public class Test +{ + void M() + { + ref Span p1 = ref stackalloc int [3] { 1, 2, 3 }; + ref Span p2 = ref stackalloc int [ ] { 1, 2, 3 }; + ref Span p3 = ref stackalloc [ ] { 1, 2, 3 }; + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (7,32): error CS1525: Invalid expression term 'stackalloc' + // ref Span p1 = ref stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 32), + // (8,32): error CS1525: Invalid expression term 'stackalloc' + // ref Span p2 = ref stackalloc int [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 32), + // (9,32): error CS1525: Invalid expression term 'stackalloc' + // ref Span p3 = ref stackalloc [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(9, 32) + ); + } + + [Fact] + public void InvalidPositionForStackAllocSpan() + { + var test = @" +using System; +public class Test +{ + void M() + { + N(stackalloc int [3] { 1, 2, 3 }); + N(stackalloc int [ ] { 1, 2, 3 }); + N(stackalloc [ ] { 1, 2, 3 }); + } + void N(Span span) + { + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( + // (7,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc int [3] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 11), + // (8,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc int [] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 11), + // (9,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc [] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(9, 11) + ); + } + + [Fact] + public void CannotDotIntoStackAllocExpression() + { + var test = @" +public class Test +{ + void M() + { + int length1 = (stackalloc int [3] { 1, 2, 3 }).Length; + int length2 = (stackalloc int [ ] { 1, 2, 3 }).Length; + int length3 = (stackalloc [ ] { 1, 2, 3 }).Length; + + int length4 = stackalloc int [3] { 1, 2, 3 }.Length; + int length5 = stackalloc int [ ] { 1, 2, 3 }.Length; + int length6 = stackalloc [ ] { 1, 2, 3 }.Length; + } +} +"; + CreateCompilationWithMscorlibAndSpan(test, TestOptions.ReleaseDll).VerifyDiagnostics( + // (6,24): error CS1525: Invalid expression term 'stackalloc' + // int length1 = (stackalloc int [3] { 1, 2, 3 }).Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 24), + // (7,24): error CS1525: Invalid expression term 'stackalloc' + // int length2 = (stackalloc int [ ] { 1, 2, 3 }).Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 24), + // (8,24): error CS1525: Invalid expression term 'stackalloc' + // int length3 = (stackalloc [ ] { 1, 2, 3 }).Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 24), + // (10,23): error CS1525: Invalid expression term 'stackalloc' + // int length4 = stackalloc int [3] { 1, 2, 3 }.Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(10, 23), + // (11,23): error CS1525: Invalid expression term 'stackalloc' + // int length5 = stackalloc int [ ] { 1, 2, 3 }.Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(11, 23), + // (12,23): error CS1525: Invalid expression term 'stackalloc' + // int length6 = stackalloc [ ] { 1, 2, 3 }.Length; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(12, 23) + ); + } + + [Fact] + public void OverloadResolution_Fail() + { + var test = @" +using System; +unsafe public class Test +{ + static void Main() + { + Invoke(stackalloc int [3] { 1, 2, 3 }); + Invoke(stackalloc int [ ] { 1, 2, 3 }); + Invoke(stackalloc [ ] { 1, 2, 3 }); + } + + static void Invoke(Span shortSpan) => Console.WriteLine(""shortSpan""); + static void Invoke(Span boolSpan) => Console.WriteLine(""boolSpan""); + static void Invoke(int* intPointer) => Console.WriteLine(""intPointer""); + static void Invoke(void* voidPointer) => Console.WriteLine(""voidPointer""); +} +"; + CreateCompilationWithMscorlibAndSpan(test, TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (7,16): error CS1525: Invalid expression term 'stackalloc' + // Invoke(stackalloc int[3] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 16), + // (8,16): error CS1525: Invalid expression term 'stackalloc' + // Invoke(stackalloc int[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 16), + // (9,16): error CS1525: Invalid expression term 'stackalloc' + // Invoke(stackalloc[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(9, 16) + ); + } + + [Fact] + public void StackAllocWithDynamic() + { + CreateStandardCompilation(@" +class Program +{ + static void Main() + { + dynamic d = 1; + var d1 = stackalloc dynamic [3] { d }; + var d2 = stackalloc dynamic [ ] { d }; + var d3 = stackalloc [ ] { d }; + } +}").VerifyDiagnostics( + // (7,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // var d1 = stackalloc dynamic [3] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "dynamic").WithArguments("dynamic").WithLocation(7, 29), + // (7,18): error CS0847: An array initializer of length '3' is expected + // var d1 = stackalloc dynamic [3] { d }; + Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc dynamic [3] { d }").WithArguments("3").WithLocation(7, 18), + // (8,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // var d2 = stackalloc dynamic [ ] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "dynamic").WithArguments("dynamic").WithLocation(8, 29), + // (9,18): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // var d3 = stackalloc [ ] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc [ ] { d }").WithArguments("dynamic").WithLocation(9, 18), + // (9,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var d3 = stackalloc [ ] { d }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc [ ] { d }").WithLocation(9, 18) + ); + } + + [Fact] + public void StackAllocWithDynamicSpan() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Program +{ + static void Main() + { + dynamic d = 1; + Span d1 = stackalloc dynamic [3] { d }; + Span d2 = stackalloc dynamic [ ] { d }; + Span d3 = stackalloc [ ] { d }; + } +}").VerifyDiagnostics( + // (8,39): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // Span d1 = stackalloc dynamic [3] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "dynamic").WithArguments("dynamic").WithLocation(8, 39), + // (8,28): error CS0847: An array initializer of length '3' is expected + // Span d1 = stackalloc dynamic [3] { d }; + Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc dynamic [3] { d }").WithArguments("3").WithLocation(8, 28), + // (9,39): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // Span d2 = stackalloc dynamic [ ] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "dynamic").WithArguments("dynamic").WithLocation(9, 39), + // (10,28): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('dynamic') + // Span d3 = stackalloc [ ] { d }; + Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc [ ] { d }").WithArguments("dynamic").WithLocation(10, 28) + ); + } + + [Fact] + public void StackAllocAsArgument() + { + CreateStandardCompilation(@" +class Program +{ + static void N(object p) { } + + static void Main() + { + N(stackalloc int [3] { 1, 2, 3 }); + N(stackalloc int [ ] { 1, 2, 3 }); + N(stackalloc [ ] { 1, 2, 3 }); + } +}").VerifyDiagnostics( + // (8,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc int[3] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 11), + // (9,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc int[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(9, 11), + // (10,11): error CS1525: Invalid expression term 'stackalloc' + // N(stackalloc[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(10, 11) + ); + } + + [Fact] + public void StackAllocInParenthesis() + { + CreateStandardCompilation(@" +class Program +{ + static void Main() + { + var x1 = (stackalloc int [3] { 1, 2, 3 }); + var x2 = (stackalloc int [ ] { 1, 2, 3 }); + var x3 = (stackalloc [ ] { 1, 2, 3 }); + } +}").VerifyDiagnostics( + // (6,19): error CS1525: Invalid expression term 'stackalloc' + // var x1 = (stackalloc int[3] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 19), + // (7,19): error CS1525: Invalid expression term 'stackalloc' + // var x2 = (stackalloc int[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 19), + // (8,19): error CS1525: Invalid expression term 'stackalloc' + // var x3 = (stackalloc[] { 1, 2, 3 }); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 19) + ); + } + + [Fact] + public void StackAllocInNullConditionalOperator() + { + CreateStandardCompilation(@" +class Program +{ + static void Main() + { + var x1 = stackalloc int [3] { 1, 2, 3 } ?? stackalloc int [3] { 1, 2, 3 }; + var x2 = stackalloc int [ ] { 1, 2, 3 } ?? stackalloc int [ ] { 1, 2, 3 }; + var x3 = stackalloc [ ] { 1, 2, 3 } ?? stackalloc [ ] { 1, 2, 3 }; + } +}").VerifyDiagnostics( + // (6,18): error CS1525: Invalid expression term 'stackalloc' + // var x1 = stackalloc int [3] { 1, 2, 3 } ?? stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 18), + // (6,52): error CS1525: Invalid expression term 'stackalloc' + // var x1 = stackalloc int [3] { 1, 2, 3 } ?? stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 52), + // (7,18): error CS1525: Invalid expression term 'stackalloc' + // var x2 = stackalloc int [] { 1, 2, 3 } ?? stackalloc int [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 18), + // (7,52): error CS1525: Invalid expression term 'stackalloc' + // var x2 = stackalloc int [] { 1, 2, 3 } ?? stackalloc int [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 52), + // (8,18): error CS1525: Invalid expression term 'stackalloc' + // var x3 = stackalloc [] { 1, 2, 3 } ?? stackalloc [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 18), + // (8,52): error CS1525: Invalid expression term 'stackalloc' + // var x3 = stackalloc [] { 1, 2, 3 } ?? stackalloc [] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(8, 52) + ); + } + + [Fact] + public void StackAllocInCastAndConditionalOperator() + { + CreateCompilationWithMscorlibAndSpan(@" +using System; +class Test +{ + public void Method() + { + Test value1 = true ? new Test() : (Test)stackalloc int [3] { 1, 2, 3 }; + Test value2 = true ? new Test() : (Test)stackalloc int [ ] { 1, 2, 3 }; + Test value3 = true ? new Test() : (Test)stackalloc [ ] { 1, 2, 3 }; + } + + public static explicit operator Test(Span value) + { + return new Test(); + } +}", TestOptions.ReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void ERR_StackallocInCatchFinally_Catch() + { + var text = @" +unsafe class C +{ + int x = M(() => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* q1 = stackalloc int [3] { 1, 2, 3 }; + int* q2 = stackalloc int [ ] { 1, 2, 3 }; + int* q3 = stackalloc [ ] { 1, 2, 3 }; + } + catch + { + int* err11 = stackalloc int [3] { 1, 2, 3 }; + int* err12 = stackalloc int [ ] { 1, 2, 3 }; + int* err13 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + catch + { + int* err21 = stackalloc int [3] { 1, 2, 3 }; + int* err22 = stackalloc int [ ] { 1, 2, 3 }; + int* err23 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + } + catch + { + int* err31 = stackalloc int [3] { 1, 2, 3 }; + int* err32 = stackalloc int [ ] { 1, 2, 3 }; + int* err33 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + }); + + static int M(System.Action action) + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* q1 = stackalloc int [3] { 1, 2, 3 }; + int* q2 = stackalloc int [ ] { 1, 2, 3 }; + int* q3 = stackalloc [ ] { 1, 2, 3 }; + } + catch + { + int* err41 = stackalloc int [3] { 1, 2, 3 }; + int* err42 = stackalloc int [ ] { 1, 2, 3 }; + int* err43 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + catch + { + int* err51 = stackalloc int [3] { 1, 2, 3 }; + int* err52 = stackalloc int [ ] { 1, 2, 3 }; + int* err53 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + } + catch + { + int* err61 = stackalloc int [3] { 1, 2, 3 }; + int* err62 = stackalloc int [ ] { 1, 2, 3 }; + int* err63 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + return 0; + } +} +"; + CreateStandardCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (23,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err11 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(23, 34), + // (24,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err12 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(24, 34), + // (25,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err13 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(25, 34), + // (31,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err21 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(31, 26), + // (32,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err22 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(32, 26), + // (33,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err23 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(33, 26), + // (45,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err31 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(45, 34), + // (46,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err32 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(46, 34), + // (47,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err33 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(47, 34), + // (72,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err41 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(72, 34), + // (73,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err42 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(73, 34), + // (74,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err43 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(74, 34), + // (80,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err51 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(80, 26), + // (81,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err52 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(81, 26), + // (82,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err53 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(82, 26), + // (94,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err61 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(94, 34), + // (95,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err62 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(95, 34), + // (96,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err63 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(96, 34) + ); + } + + [Fact] + public void ERR_StackallocInCatchFinally_Finally() + { + var text = @" +unsafe class C +{ + int x = M(() => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* q1 = stackalloc int [3] { 1, 2, 3 }; + int* q2 = stackalloc int [ ] { 1, 2, 3 }; + int* q3 = stackalloc [ ] { 1, 2, 3 }; + } + finally + { + int* err11 = stackalloc int [3] { 1, 2, 3 }; + int* err12 = stackalloc int [ ] { 1, 2, 3 }; + int* err13 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + finally + { + int* err21 = stackalloc int [3] { 1, 2, 3 }; + int* err22 = stackalloc int [ ] { 1, 2, 3 }; + int* err23 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + } + finally + { + int* err31 = stackalloc int [3] { 1, 2, 3 }; + int* err32 = stackalloc int [ ] { 1, 2, 3 }; + int* err33 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + }); + + static int M(System.Action action) + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* q1 = stackalloc int [3] { 1, 2, 3 }; + int* q2 = stackalloc int [ ] { 1, 2, 3 }; + int* q3 = stackalloc [ ] { 1, 2, 3 }; + } + finally + { + int* err41 = stackalloc int [3] { 1, 2, 3 }; + int* err42 = stackalloc int [ ] { 1, 2, 3 }; + int* err43 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + finally + { + int* err51 = stackalloc int [3] { 1, 2, 3 }; + int* err52 = stackalloc int [ ] { 1, 2, 3 }; + int* err53 = stackalloc [ ] { 1, 2, 3 }; + System.Action a = () => + { + try + { + // fine + int* p1 = stackalloc int [3] { 1, 2, 3 }; + int* p2 = stackalloc int [ ] { 1, 2, 3 }; + int* p3 = stackalloc [ ] { 1, 2, 3 }; + } + finally + { + int* err61 = stackalloc int [3] { 1, 2, 3 }; + int* err62 = stackalloc int [ ] { 1, 2, 3 }; + int* err63 = stackalloc [ ] { 1, 2, 3 }; + } + }; + } + return 0; + } +} +"; + CreateStandardCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (23,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err11 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(23, 34), + // (24,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err12 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(24, 34), + // (25,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err13 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(25, 34), + // (31,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err21 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(31, 26), + // (32,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err22 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(32, 26), + // (33,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err23 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(33, 26), + // (45,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err31 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(45, 34), + // (46,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err32 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(46, 34), + // (47,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err33 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(47, 34), + // (72,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err41 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(72, 34), + // (73,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err42 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(73, 34), + // (74,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err43 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(74, 34), + // (80,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err51 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(80, 26), + // (81,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err52 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(81, 26), + // (82,26): error CS0255: stackalloc may not be used in a catch or finally block + // int* err53 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(82, 26), + // (94,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err61 = stackalloc int [3] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [3] { 1, 2, 3 }").WithLocation(94, 34), + // (95,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err62 = stackalloc int [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc int [ ] { 1, 2, 3 }").WithLocation(95, 34), + // (96,34): error CS0255: stackalloc may not be used in a catch or finally block + // int* err63 = stackalloc [ ] { 1, 2, 3 }; + Diagnostic(ErrorCode.ERR_StackallocInCatchFinally, "stackalloc [ ] { 1, 2, 3 }").WithLocation(96, 34) + ); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 2ef4b96822138..7fb67b666385f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -7463,33 +7463,37 @@ static void Main() } "; CreateStandardCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,31): error CS1575: A stackalloc expression requires [] after type + // (6,34): error CS1586: Array creation must have array size or array initializer // { int* p = stackalloc int[]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[]"), + Diagnostic(ErrorCode.ERR_MissingArraySize, "[]").WithLocation(6, 34), + // (8,34): error CS1586: Array creation must have array size or array initializer + // { int* p = stackalloc int[][]; } + Diagnostic(ErrorCode.ERR_MissingArraySize, "[]").WithLocation(8, 34), + // (9,34): error CS1586: Array creation must have array size or array initializer + // { int* p = stackalloc int[][1]; } + Diagnostic(ErrorCode.ERR_MissingArraySize, "[]").WithLocation(9, 34), + // (9,37): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) + // { int* p = stackalloc int[][1]; } + Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "1").WithLocation(9, 37), + // (11,38): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) + // { int* p = stackalloc int[1][1]; } + Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "1").WithLocation(11, 38), // (7,31): error CS1575: A stackalloc expression requires [] after type // { int* p = stackalloc int[1, 1]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1, 1]"), + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1, 1]").WithLocation(7, 31), // (8,31): error CS1575: A stackalloc expression requires [] after type // { int* p = stackalloc int[][]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[][]"), + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[][]").WithLocation(8, 31), // (9,31): error CS1575: A stackalloc expression requires [] after type // { int* p = stackalloc int[][1]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[][1]"), + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[][1]").WithLocation(9, 31), // (10,31): error CS1575: A stackalloc expression requires [] after type // { int* p = stackalloc int[1][]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1][]"), + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1][]").WithLocation(10, 31), // (11,31): error CS1575: A stackalloc expression requires [] after type // { int* p = stackalloc int[1][1]; } - Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1][1]"), - - // CONSIDER: these are plausible, but not ideal. - - // (9,37): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) - // { int* p = stackalloc int[][1]; } - Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "1"), - // (11,38): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) - // { int* p = stackalloc int[1][1]; } - Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "1")); + Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int[1][1]").WithLocation(11, 31) + ); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 1a1a9507640c8..8f73b5bd2dc0b 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -286,7 +286,12 @@ private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.ImplicitArray private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.StackAllocArrayCreationExpressionSyntax GenerateStackAllocArrayCreationExpression() { - return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), GenerateIdentifierName()); + return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), GenerateIdentifierName(), null); + } + + private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.ImplicitStackAllocArrayCreationExpressionSyntax GenerateImplicitStackAllocArrayCreationExpression() + { + return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.ImplicitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.OpenBracketToken), Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.CloseBracketToken), GenerateInitializerExpression()); } private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.QueryExpressionSyntax GenerateQueryExpression() @@ -1686,6 +1691,20 @@ public void TestStackAllocArrayCreationExpressionFactoryAndProperties() Assert.Equal(SyntaxKind.StackAllocKeyword, node.StackAllocKeyword.Kind); Assert.NotNull(node.Type); + Assert.Null(node.Initializer); + + AttachAndCheckDiagnostics(node); + } + + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionFactoryAndProperties() + { + var node = GenerateImplicitStackAllocArrayCreationExpression(); + + Assert.Equal(SyntaxKind.StackAllocKeyword, node.StackAllocKeyword.Kind); + Assert.Equal(SyntaxKind.OpenBracketToken, node.OpenBracketToken.Kind); + Assert.Equal(SyntaxKind.CloseBracketToken, node.CloseBracketToken.Kind); + Assert.NotNull(node.Initializer); AttachAndCheckDiagnostics(node); } @@ -5075,6 +5094,32 @@ public void TestStackAllocArrayCreationExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionTokenDeleteRewriter() + { + var oldNode = GenerateImplicitStackAllocArrayCreationExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionIdentityRewriter() + { + var oldNode = GenerateImplicitStackAllocArrayCreationExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestQueryExpressionTokenDeleteRewriter() { @@ -9205,7 +9250,12 @@ private static ImplicitArrayCreationExpressionSyntax GenerateImplicitArrayCreati private static StackAllocArrayCreationExpressionSyntax GenerateStackAllocArrayCreationExpression() { - return SyntaxFactory.StackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), GenerateIdentifierName()); + return SyntaxFactory.StackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), GenerateIdentifierName(), default(InitializerExpressionSyntax)); + } + + private static ImplicitStackAllocArrayCreationExpressionSyntax GenerateImplicitStackAllocArrayCreationExpression() + { + return SyntaxFactory.ImplicitStackAllocArrayCreationExpression(SyntaxFactory.Token(SyntaxKind.StackAllocKeyword), SyntaxFactory.Token(SyntaxKind.OpenBracketToken), SyntaxFactory.Token(SyntaxKind.CloseBracketToken), GenerateInitializerExpression()); } private static QueryExpressionSyntax GenerateQueryExpression() @@ -10605,7 +10655,21 @@ public void TestStackAllocArrayCreationExpressionFactoryAndProperties() Assert.Equal(SyntaxKind.StackAllocKeyword, node.StackAllocKeyword.Kind()); Assert.NotNull(node.Type); - var newNode = node.WithStackAllocKeyword(node.StackAllocKeyword).WithType(node.Type); + Assert.Null(node.Initializer); + var newNode = node.WithStackAllocKeyword(node.StackAllocKeyword).WithType(node.Type).WithInitializer(node.Initializer); + Assert.Equal(node, newNode); + } + + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionFactoryAndProperties() + { + var node = GenerateImplicitStackAllocArrayCreationExpression(); + + Assert.Equal(SyntaxKind.StackAllocKeyword, node.StackAllocKeyword.Kind()); + Assert.Equal(SyntaxKind.OpenBracketToken, node.OpenBracketToken.Kind()); + Assert.Equal(SyntaxKind.CloseBracketToken, node.CloseBracketToken.Kind()); + Assert.NotNull(node.Initializer); + var newNode = node.WithStackAllocKeyword(node.StackAllocKeyword).WithOpenBracketToken(node.OpenBracketToken).WithCloseBracketToken(node.CloseBracketToken).WithInitializer(node.Initializer); Assert.Equal(node, newNode); } @@ -13994,6 +14058,32 @@ public void TestStackAllocArrayCreationExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionTokenDeleteRewriter() + { + var oldNode = GenerateImplicitStackAllocArrayCreationExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestImplicitStackAllocArrayCreationExpressionIdentityRewriter() + { + var oldNode = GenerateImplicitStackAllocArrayCreationExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestQueryExpressionTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index e9d3ac13b71fd..4b492376cbad9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -62,9 +62,9 @@ internal void UsingStatement(string text, params DiagnosticDescription[] expecte UsingNode(node); } - internal void UsingExpression(string text, params DiagnosticDescription[] expectedErrors) + internal void UsingExpression(string text, ParseOptions options, params DiagnosticDescription[] expectedErrors) { - var node = SyntaxFactory.ParseExpression(text); + var node = SyntaxFactory.ParseExpression(text, options: options); // we validate the text roundtrips Assert.Equal(text, node.ToFullString()); var actualErrors = node.GetDiagnostics(); @@ -72,6 +72,11 @@ internal void UsingExpression(string text, params DiagnosticDescription[] expect UsingNode(node); } + internal void UsingExpression(string text, params DiagnosticDescription[] expectedErrors) + { + UsingExpression(text, options: null, expectedErrors); + } + /// /// Parses given string and initializes a depth-first preorder enumerator. /// diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerTests.cs new file mode 100644 index 0000000000000..e586f8a56e03f --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerTests.cs @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing +{ + [CompilerTrait(CompilerFeature.StackAllocInitializer)] + public class StackAllocInitializerTests : ParsingTests + { + public StackAllocInitializerTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void StackAllocInitializer_01() + { + UsingExpression("stackalloc int[] { 42 }", options: TestOptions.Regular7, + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(1, 1)); + N(SyntaxKind.StackAllocArrayCreationExpression); + { + N(SyntaxKind.StackAllocKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.ArrayInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "42"); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void StackAllocInitializer_02() + { + UsingExpression("stackalloc int[1] { 42 }", options: TestOptions.Regular7, + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(1, 1)); + N(SyntaxKind.StackAllocArrayCreationExpression); + { + N(SyntaxKind.StackAllocKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.ArrayInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "42"); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void StackAllocInitializer_03() + { + UsingExpression("stackalloc[] { 42 }", options: TestOptions.Regular7, + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(1, 1)); + N(SyntaxKind.ImplicitStackAllocArrayCreationExpression); + { + N(SyntaxKind.StackAllocKeyword); + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.ArrayInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "42"); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void StackAllocInitializer_04() + { + UsingExpression("stackalloc[1] { 42 }", options: TestOptions.Regular7, + // (1,1): error CS8107: Feature 'stackalloc initializer' is not available in C# 7.0. Please use language version 7.3 or greater. + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "stackalloc").WithArguments("stackalloc initializer", "7.3").WithLocation(1, 1), + // (1,12): error CS1003: Syntax error, ']' expected + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_SyntaxError, "1").WithArguments("]", "").WithLocation(1, 12), + // (1,12): error CS1514: { expected + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_LbraceExpected, "1").WithLocation(1, 12), + // (1,13): error CS1003: Syntax error, ',' expected + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_SyntaxError, "]").WithArguments(",", "]").WithLocation(1, 13), + // (1,15): error CS1003: Syntax error, ',' expected + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(1, 15), + // (1,21): error CS1513: } expected + // stackalloc[1] { 42 } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 21)); + N(SyntaxKind.ImplicitStackAllocArrayCreationExpression); + { + N(SyntaxKind.StackAllocKeyword); + N(SyntaxKind.OpenBracketToken); + M(SyntaxKind.CloseBracketToken); + N(SyntaxKind.ArrayInitializerExpression); + { + M(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.ArrayInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "42"); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + } +} diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 761c8a7135082..e367e730aae66 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Reflection.Metadata; using Roslyn.Utilities; +using static System.Linq.ImmutableArrayExtensions; namespace Microsoft.CodeAnalysis.CodeGen { @@ -87,6 +88,29 @@ internal void EmitArrayBlockInitializer(ImmutableArray data, SyntaxNode sy EmitToken(initializeArray, syntaxNode, diagnostics); } + internal void EmitStackAllocBlockInitializer(ImmutableArray data, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + { + if (data.All(datum => datum == data[0])) + { + // All bytes are the same, no need for metadata blob + + EmitOpCode(ILOpCode.Dup); + EmitIntConstant(data[0]); + EmitIntConstant(data.Length); + EmitOpCode(ILOpCode.Initblk, -3); + } + else + { + var field = module.GetFieldForData(data, syntaxNode, diagnostics); + + EmitOpCode(ILOpCode.Dup); + EmitOpCode(ILOpCode.Ldsflda); + EmitToken(field, syntaxNode, diagnostics); + EmitIntConstant(data.Length); + EmitOpCode(ILOpCode.Cpblk, -3); + } + } + /// /// Mark current IL position with a label /// diff --git a/src/Test/Utilities/Portable/TestResource.resx b/src/Test/Utilities/Portable/TestResource.resx index b7f0f026124bb..f33c01a9193e2 100644 --- a/src/Test/Utilities/Portable/TestResource.resx +++ b/src/Test/Utilities/Portable/TestResource.resx @@ -386,7 +386,7 @@ namespace My { *intref = 1; } - fixed (int* p = stackalloc int[100]) + fixed (int* p = stackalloc int[] { 100 }, q = stackalloc[] { 100 }) { *intref = 1; } diff --git a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs index 8d176ca617c63..58b67f351778d 100644 --- a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs +++ b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs @@ -28,5 +28,6 @@ public enum CompilerFeature PrivateProtected, PEVerifyCompat, RefConditionalOperator, + StackAllocInitializer, } }