提交 8f2b6657 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #22162 from VSadov/stackallocType

Making default type of stackalloc expression to be Span<T> when not directly in an initializer
...@@ -1887,6 +1887,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1887,6 +1887,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
case BoundKind.Local: case BoundKind.Local:
return ((BoundLocal)expr).LocalSymbol.ValEscapeScope; return ((BoundLocal)expr).LocalSymbol.ValEscapeScope;
case BoundKind.StackAllocArrayCreation:
case BoundKind.ConvertedStackAllocExpression: case BoundKind.ConvertedStackAllocExpression:
return Binder.TopLevelScope; return Binder.TopLevelScope;
...@@ -2054,6 +2055,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -2054,6 +2055,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
} }
return true; return true;
case BoundKind.StackAllocArrayCreation:
case BoundKind.ConvertedStackAllocExpression: case BoundKind.ConvertedStackAllocExpression:
if (escapeTo < Binder.TopLevelScope) if (escapeTo < Binder.TopLevelScope)
{ {
......
...@@ -339,7 +339,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre ...@@ -339,7 +339,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre
throw ExceptionUtilities.UnexpectedValue(conversion.Kind); throw ExceptionUtilities.UnexpectedValue(conversion.Kind);
} }
var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, conversion.Kind, stackAllocType, boundStackAlloc.HasErrors); var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, stackAllocType, boundStackAlloc.HasErrors);
var underlyingConversion = conversion.UnderlyingConversions.Single(); var underlyingConversion = conversion.UnderlyingConversions.Single();
return CreateConversion(syntax, convertedNode, underlyingConversion, isCast, destination, diagnostics); return CreateConversion(syntax, convertedNode, underlyingConversion, isCast, destination, diagnostics);
......
...@@ -3016,8 +3016,9 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial ...@@ -3016,8 +3016,9 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial
StackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics) StackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics)
{ {
bool hasErrors = false; bool hasErrors = false;
var inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalSpanStackAllocPosition();
if (!IsInMethodBody && !IsLocalFunctionsScopeBinder) if (!inLegalPosition)
{ {
hasErrors = true; hasErrors = true;
diagnostics.Add( diagnostics.Add(
...@@ -3103,7 +3104,20 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial ...@@ -3103,7 +3104,20 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial
} }
} }
return new BoundStackAllocArrayCreation(node, elementType, count, type: null, hasErrors: hasErrors || typeHasErrors); TypeSymbol type = null;
if (inLegalPosition && !node.IsVariableDeclarationInitialization())
{
CheckFeatureAvailability(node, MessageID.IDS_FeatureRefStructs, diagnostics);
GetWellKnownTypeMember(Compilation, WellKnownMember.System_Span_T__ctor, diagnostics, syntax: node);
var spanType = GetWellKnownType(WellKnownType.System_Span_T, diagnostics, node);
if (!spanType.IsErrorType())
{
type = spanType.Construct(elementType);
}
}
return new BoundStackAllocArrayCreation(node, elementType, count, type, hasErrors: hasErrors || typeHasErrors);
} }
private static int? GetIntegerConstantForArraySize(BoundExpression expression) private static int? GetIntegerConstantForArraySize(BoundExpression expression)
......
...@@ -287,46 +287,36 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re ...@@ -287,46 +287,36 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics) public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{ {
Debug.Assert((object)sourceExpression.Type == null);
Debug.Assert(sourceExpression.ElementType != null);
var pointerConversion = default(Conversion);
if (sourceExpression.Syntax.IsVariableDeclarationInitialization()) if (sourceExpression.Syntax.IsVariableDeclarationInitialization())
{ {
Debug.Assert((object)sourceExpression.Type == null);
Debug.Assert(sourceExpression.ElementType != null);
var pointerConversion = default(Conversion);
var sourceAsPointer = new PointerTypeSymbol(sourceExpression.ElementType); var sourceAsPointer = new PointerTypeSymbol(sourceExpression.ElementType);
pointerConversion = ClassifyImplicitConversionFromType(sourceAsPointer, destination, ref useSiteDiagnostics); pointerConversion = ClassifyImplicitConversionFromType(sourceAsPointer, destination, ref useSiteDiagnostics);
}
if (pointerConversion.IsValid)
{
// Report unsafe errors
_binder.ReportUnsafeIfNotAllowed(sourceExpression.Syntax.Location, ref useSiteDiagnostics);
return Conversion.MakeStackAllocToPointerType(pointerConversion); if (pointerConversion.IsValid)
} {
else // Report unsafe errors
{ _binder.ReportUnsafeIfNotAllowed(sourceExpression.Syntax.Location, ref useSiteDiagnostics);
var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics).Construct(sourceExpression.ElementType);
var spanConversion = ClassifyImplicitConversionFromType(spanType, destination, ref useSiteDiagnostics);
if (spanConversion.Exists) return Conversion.MakeStackAllocToPointerType(pointerConversion);
}
else
{ {
// Report errors if Span ctor is missing, or using an older C# version var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics).Construct(sourceExpression.ElementType);
Binder.CheckFeatureAvailability(sourceExpression.Syntax, MessageID.IDS_FeatureRefStructs, ref useSiteDiagnostics); var spanConversion = ClassifyImplicitConversionFromType(spanType, destination, ref useSiteDiagnostics);
Binder.GetWellKnownTypeMember(_binder.Compilation, WellKnownMember.System_Span_T__ctor, out DiagnosticInfo memberDiagnosticInfo);
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, memberDiagnosticInfo);
if (!sourceExpression.Syntax.IsLegalSpanStackAllocPosition()) if (spanConversion.Exists)
{ {
// Because the instruction cannot have any values on the stack before CLR execution. // Report errors if Span ctor is missing, or using an older C# version
// Limit it to assignments and conditional expressions for now. Binder.CheckFeatureAvailability(sourceExpression.Syntax, MessageID.IDS_FeatureRefStructs, ref useSiteDiagnostics);
// https://github.com/dotnet/roslyn/issues/22046 Binder.GetWellKnownTypeMember(_binder.Compilation, WellKnownMember.System_Span_T__ctor, out DiagnosticInfo memberDiagnosticInfo);
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, memberDiagnosticInfo);
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, new CSDiagnosticInfo(ErrorCode.ERR_InvalidExprTerm, SyntaxFacts.GetText(SyntaxKind.StackAllocKeyword))); return Conversion.MakeStackAllocToSpanType(spanConversion);
} }
return Conversion.MakeStackAllocToSpanType(spanConversion);
} }
} }
......
...@@ -1435,13 +1435,9 @@ ...@@ -1435,13 +1435,9 @@
<Field Name="Count" Type="BoundExpression"/> <Field Name="Count" Type="BoundExpression"/>
</Node> </Node>
<Node Name="BoundConvertedStackAllocExpression" Base="BoundExpression"> <Node Name="BoundConvertedStackAllocExpression" Base="BoundStackAllocArrayCreation">
<!-- Non-null type is required for this node kind --> <!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/> <Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="ElementType" Type="TypeSymbol" Null="disallow"/>
<Field Name="Count" Type="BoundExpression"/>
<Field Name="ConversionKind" Type="ConversionKind" Null="allow"/>
</Node> </Node>
<Node Name="BoundFieldAccess" Base="BoundExpression"> <Node Name="BoundFieldAccess" Base="BoundExpression">
......
...@@ -5226,8 +5226,19 @@ public BoundArrayInitialization Update(ImmutableArray<BoundExpression> initializ ...@@ -5226,8 +5226,19 @@ public BoundArrayInitialization Update(ImmutableArray<BoundExpression> initializ
} }
} }
internal sealed partial class BoundStackAllocArrayCreation : BoundExpression internal partial class BoundStackAllocArrayCreation : BoundExpression
{ {
protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false)
: base(kind, syntax, type, hasErrors)
{
Debug.Assert(elementType != null, "Field 'elementType' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(count != null, "Field 'count' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.ElementType = elementType;
this.Count = count;
}
public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false) public BoundStackAllocArrayCreation(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.StackAllocArrayCreation, syntax, type, hasErrors || count.HasErrors()) : base(BoundKind.StackAllocArrayCreation, syntax, type, hasErrors || count.HasErrors())
{ {
...@@ -5261,38 +5272,29 @@ public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpressi ...@@ -5261,38 +5272,29 @@ public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpressi
} }
} }
internal sealed partial class BoundConvertedStackAllocExpression : BoundExpression internal sealed partial class BoundConvertedStackAllocExpression : BoundStackAllocArrayCreation
{ {
public BoundConvertedStackAllocExpression(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, ConversionKind conversionKind, TypeSymbol type, bool hasErrors = false) public BoundConvertedStackAllocExpression(SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.ConvertedStackAllocExpression, syntax, type, hasErrors || count.HasErrors()) : base(BoundKind.ConvertedStackAllocExpression, syntax, elementType, count, type, hasErrors || count.HasErrors())
{ {
Debug.Assert(elementType != null, "Field 'elementType' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(elementType != null, "Field 'elementType' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(count != null, "Field 'count' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(count != null, "Field 'count' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.ElementType = elementType;
this.Count = count;
this.ConversionKind = conversionKind;
} }
public TypeSymbol ElementType { get; }
public BoundExpression Count { get; }
public ConversionKind ConversionKind { get; }
public override BoundNode Accept(BoundTreeVisitor visitor) public override BoundNode Accept(BoundTreeVisitor visitor)
{ {
return visitor.VisitConvertedStackAllocExpression(this); return visitor.VisitConvertedStackAllocExpression(this);
} }
public BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, ConversionKind conversionKind, TypeSymbol type) public new BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, TypeSymbol type)
{ {
if (elementType != this.ElementType || count != this.Count || conversionKind != this.ConversionKind || type != this.Type) if (elementType != this.ElementType || count != this.Count || type != this.Type)
{ {
var result = new BoundConvertedStackAllocExpression(this.Syntax, elementType, count, conversionKind, type, this.HasErrors); var result = new BoundConvertedStackAllocExpression(this.Syntax, elementType, count, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated; result.WasCompilerGenerated = this.WasCompilerGenerated;
return result; return result;
} }
...@@ -9175,7 +9177,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack ...@@ -9175,7 +9177,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack
BoundExpression count = (BoundExpression)this.Visit(node.Count); BoundExpression count = (BoundExpression)this.Visit(node.Count);
TypeSymbol elementType = this.VisitType(node.ElementType); TypeSymbol elementType = this.VisitType(node.ElementType);
TypeSymbol type = this.VisitType(node.Type); TypeSymbol type = this.VisitType(node.Type);
return node.Update(elementType, count, node.ConversionKind, type); return node.Update(elementType, count, type);
} }
public override BoundNode VisitFieldAccess(BoundFieldAccess node) public override BoundNode VisitFieldAccess(BoundFieldAccess node)
{ {
...@@ -10637,7 +10639,6 @@ public override TreeDumperNode VisitConvertedStackAllocExpression(BoundConverted ...@@ -10637,7 +10639,6 @@ public override TreeDumperNode VisitConvertedStackAllocExpression(BoundConverted
{ {
new TreeDumperNode("elementType", node.ElementType, null), new TreeDumperNode("elementType", node.ElementType, null),
new TreeDumperNode("count", null, new TreeDumperNode[] { Visit(node.Count, null) }), new TreeDumperNode("count", null, new TreeDumperNode[] { Visit(node.Count, null) }),
new TreeDumperNode("conversionKind", node.ConversionKind, null),
new TreeDumperNode("type", node.Type, null) new TreeDumperNode("type", node.Type, null)
} }
); );
......
...@@ -10,48 +10,48 @@ namespace Microsoft.CodeAnalysis.CSharp ...@@ -10,48 +10,48 @@ namespace Microsoft.CodeAnalysis.CSharp
internal sealed partial class LocalRewriter internal sealed partial class LocalRewriter
{ {
public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression stackAllocNode) public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression stackAllocNode)
{
return VisitStackAllocArrayCreation(stackAllocNode);
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode)
{ {
var rewrittenCount = VisitExpression(stackAllocNode.Count); var rewrittenCount = VisitExpression(stackAllocNode.Count);
var type = stackAllocNode.Type;
if (rewrittenCount.ConstantValue?.Int32Value == 0) if (rewrittenCount.ConstantValue?.Int32Value == 0)
{ {
// either default(span) or nullptr // either default(span) or nullptr
return _factory.Default(stackAllocNode.Type); return _factory.Default(type);
} }
var conversionKind = stackAllocNode.ConversionKind;
var elementType = stackAllocNode.ElementType; var elementType = stackAllocNode.ElementType;
switch (conversionKind) if (type.IsPointerType())
{ {
case ConversionKind.StackAllocToPointerType: var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType);
{ return new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type);
var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); }
return stackAllocNode.Update(elementType, stackSize, conversionKind, stackAllocNode.Type); else if (type.IsSpanType())
} {
case ConversionKind.StackAllocToSpanType: var spanType = (NamedTypeSymbol)stackAllocNode.Type;
{ var countTemp = _factory.StoreToTemp(rewrittenCount, out BoundAssignmentOperator countTempAssignment);
Debug.Assert(stackAllocNode.Type.IsSpanType()); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType);
stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, spanType);
var spanType = (NamedTypeSymbol)stackAllocNode.Type;
var countTemp = _factory.StoreToTemp(rewrittenCount, out BoundAssignmentOperator countTempAssignment); var spanCtor = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor).SymbolAsMember(spanType);
var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); var ctorCall = _factory.New(spanCtor, stackAllocNode, countTemp);
stackAllocNode = stackAllocNode.Update(elementType, stackSize, conversionKind, spanType);
return new BoundSequence(
var spanCtor = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor).SymbolAsMember(spanType); syntax: stackAllocNode.Syntax,
var ctorCall = _factory.New(spanCtor, stackAllocNode, countTemp); locals: ImmutableArray.Create(countTemp.LocalSymbol),
sideEffects: ImmutableArray.Create<BoundExpression>(countTempAssignment),
return new BoundSequence( value: ctorCall,
syntax: stackAllocNode.Syntax, type: spanType);
locals: ImmutableArray.Create(countTemp.LocalSymbol), }
sideEffects: ImmutableArray.Create<BoundExpression>(countTempAssignment), else
value: ctorCall, {
type: spanType); throw ExceptionUtilities.UnexpectedValue(type);
}
default:
{
throw ExceptionUtilities.UnexpectedValue(conversionKind);
}
} }
} }
......
...@@ -1053,7 +1053,7 @@ unsafe public static void Main() ...@@ -1053,7 +1053,7 @@ unsafe public static void Main()
var span1 = condition ? stackalloc int[1] : new Span<int>(null, 2); var span1 = condition ? stackalloc int[1] : new Span<int>(null, 2);
Console.Write(span1.Length); Console.Write(span1.Length);
var span2 = condition ? new Span<int>(null, 3) : stackalloc int[4]; var span2 = condition ? stackalloc int[1] : stackalloc int[4];
Console.Write(span2.Length); Console.Write(span2.Length);
} }
}", TestOptions.UnsafeReleaseExe); }", TestOptions.UnsafeReleaseExe);
......
...@@ -227,7 +227,7 @@ void M() ...@@ -227,7 +227,7 @@ void M()
} }
[Fact] [Fact]
public void ConditionalExpressionOnSpan_NonConvertible() public void ConditionalExpressionOnSpan_BothStackallocSpans()
{ {
CreateCompilationWithMscorlibAndSpan(@" CreateCompilationWithMscorlibAndSpan(@"
class Test class Test
...@@ -236,10 +236,7 @@ void M() ...@@ -236,10 +236,7 @@ void M()
{ {
var x = true ? stackalloc int [10] : stackalloc int [5]; var x = true ? stackalloc int [10] : stackalloc int [5];
} }
}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( }", TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
// (6,17): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'stackalloc int[10]' and 'stackalloc int[5]'
// var x = true ? stackalloc int [10] : stackalloc int [5];
Diagnostic(ErrorCode.ERR_InvalidQM, "true ? stackalloc int [10] : stackalloc int [5]").WithArguments("stackalloc int[10]", "stackalloc int[5]").WithLocation(6, 17));
} }
[Fact] [Fact]
...@@ -317,9 +314,13 @@ void M() ...@@ -317,9 +314,13 @@ void M()
if(stackalloc int[10] == stackalloc int[10]) { } if(stackalloc int[10] == stackalloc int[10]) { }
} }
}", TestOptions.UnsafeReleaseDll).VerifyDiagnostics( }", TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,12): error CS0019: Operator '==' cannot be applied to operands of type 'stackalloc int[10]' and 'stackalloc int[10]' // (6,12): error CS1525: Invalid expression term 'stackalloc'
// if(stackalloc int[10] == stackalloc int[10]) { }
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 12),
// (6,34): error CS1525: Invalid expression term 'stackalloc'
// if(stackalloc int[10] == stackalloc int[10]) { } // if(stackalloc int[10] == stackalloc int[10]) { }
Diagnostic(ErrorCode.ERR_BadBinaryOps, "stackalloc int[10] == stackalloc int[10]").WithArguments("==", "stackalloc int[10]", "stackalloc int[10]").WithLocation(6, 12)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 34)
);
} }
[Fact] [Fact]
...@@ -435,9 +436,10 @@ void M() ...@@ -435,9 +436,10 @@ void M()
} }
"; ";
CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics(
// (7,31): error CS1510: A ref or out value must be an assignable variable // (7,31): error CS1525: Invalid expression term 'stackalloc'
// ref Span<int> p = ref stackalloc int[1]; // ref Span<int> p = ref stackalloc int[1];
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "stackalloc int[1]").WithLocation(7, 31)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 31)
);
} }
[Fact] [Fact]
...@@ -457,9 +459,10 @@ void N(Span<int> span) ...@@ -457,9 +459,10 @@ void N(Span<int> span)
} }
"; ";
CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( CreateCompilationWithMscorlibAndSpan(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics(
// (7,9): error CS1525: Invalid expression term 'stackalloc' // (7,11): error CS1525: Invalid expression term 'stackalloc'
// N(stackalloc int[1]); // N(stackalloc int[1]);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "N").WithArguments("stackalloc").WithLocation(7, 9)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 11)
);
} }
[Fact] [Fact]
...@@ -475,9 +478,10 @@ void M() ...@@ -475,9 +478,10 @@ void M()
} }
"; ";
CreateCompilationWithMscorlibAndSpan(test, TestOptions.ReleaseDll).VerifyDiagnostics( CreateCompilationWithMscorlibAndSpan(test, TestOptions.ReleaseDll).VerifyDiagnostics(
// (6,22): error CS0023: Operator '.' cannot be applied to operand of type 'stackalloc int[10]' // (6,23): error CS1525: Invalid expression term 'stackalloc'
// int length = (stackalloc int [10]).Length; // int length = (stackalloc int [10]).Length;
Diagnostic(ErrorCode.ERR_BadUnaryOp, "(stackalloc int [10]).Length").WithArguments(".", "stackalloc int[10]").WithLocation(6, 22)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 23)
);
} }
[Fact] [Fact]
...@@ -499,9 +503,10 @@ static void Main() ...@@ -499,9 +503,10 @@ static void Main()
} }
"; ";
CreateCompilationWithMscorlibAndSpan(test, TestOptions.UnsafeReleaseExe).VerifyDiagnostics( CreateCompilationWithMscorlibAndSpan(test, TestOptions.UnsafeReleaseExe).VerifyDiagnostics(
// (7,16): error CS1503: Argument 1: cannot convert from 'stackalloc int[10]' to 'Span<short>' // (7,16): error CS1525: Invalid expression term 'stackalloc'
// Invoke(stackalloc int [10]); // Invoke(stackalloc int [10]);
Diagnostic(ErrorCode.ERR_BadArgType, "stackalloc int [10]").WithArguments("1", "stackalloc int[10]", "System.Span<short>").WithLocation(7, 16)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(7, 16)
);
} }
} }
} }
...@@ -7560,7 +7560,8 @@ void M(int* p = stackalloc int[1]) ...@@ -7560,7 +7560,8 @@ void M(int* p = stackalloc int[1])
CreateStandardCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( CreateStandardCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (4,21): error CS1525: Invalid expression term 'stackalloc' // (4,21): error CS1525: Invalid expression term 'stackalloc'
// void M(int* p = stackalloc int[1]) // void M(int* p = stackalloc int[1])
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(4, 21)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(4, 21)
);
} }
[Fact] [Fact]
......
...@@ -2876,7 +2876,8 @@ static void Main(string[] args) ...@@ -2876,7 +2876,8 @@ static void Main(string[] args)
CreateStandardCompilation(text, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)).VerifyDiagnostics( CreateStandardCompilation(text, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)).VerifyDiagnostics(
// (4,30): error CS1525: Invalid expression term 'stackalloc' // (4,30): error CS1525: Invalid expression term 'stackalloc'
// int* property { get; } = stackalloc int[256]; // int* property { get; } = stackalloc int[256];
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(4, 30)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(4, 30)
);
} }
[Fact] [Fact]
public void RefPropertyWithoutGetter() public void RefPropertyWithoutGetter()
......
...@@ -4616,6 +4616,9 @@ unsafe public static int Main() ...@@ -4616,6 +4616,9 @@ unsafe public static int Main()
// (7,34): error CS1002: ; expected // (7,34): error CS1002: ; expected
// int *pp = stackalloc int 30; // int *pp = stackalloc int 30;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "30").WithLocation(7, 34), Diagnostic(ErrorCode.ERR_SemicolonExpected, "30").WithLocation(7, 34),
// (6,18): error CS1525: Invalid expression term 'stackalloc'
// int *p = stackalloc int (30);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "stackalloc").WithArguments("stackalloc").WithLocation(6, 18),
// (6,29): error CS1575: A stackalloc expression requires [] after type // (6,29): error CS1575: A stackalloc expression requires [] after type
// int *p = stackalloc int (30); // int *p = stackalloc int (30);
Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int").WithLocation(6, 29), Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int").WithLocation(6, 29),
...@@ -4624,7 +4627,8 @@ unsafe public static int Main() ...@@ -4624,7 +4627,8 @@ unsafe public static int Main()
Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int").WithLocation(7, 30), Diagnostic(ErrorCode.ERR_BadStackAllocExpr, "int").WithLocation(7, 30),
// (7,34): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement // (7,34): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
// int *pp = stackalloc int 30; // int *pp = stackalloc int 30;
Diagnostic(ErrorCode.ERR_IllegalStatement, "30").WithLocation(7, 34)); Diagnostic(ErrorCode.ERR_IllegalStatement, "30").WithLocation(7, 34)
);
} }
[Fact] [Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册