未验证 提交 1010ef61 编写于 作者: N Neal Gafter 提交者: GitHub

Determine whether a stackalloc expression is target-typed when it is bound (not later). (#40457)

Fixes #40197
上级 a3c3a44a
Bound Node Design
=================
This document discusses design principles for the bound nodes.
### The shape of the bound tree should correspond to the shape of the program's static semantics
Generally speaking, that means that there is an isomorphism between the syntax and bound nodes, except when there is a mismatch between the shape of the syntax and semantics, in which case they model the shape of the semantics. When possible, we prefer the correspondence be as direct as possible. Here are two examples that illustrate this:
1. Parenthesized expressions do not appear in the bound nodes because they have no semantic meaning.
2. Query expressions are given a semantic meaning by correspondence to a translated form, so the bound nodes may model the translated form.
### Bound nodes should capture all semantic information embedded in the syntax
A consumer of the bound nodes should not need to examine the syntax from which they were produced to understand the meaning of the bound nodes. All relevant semantic information that comes from the syntax should be summarized in the fields of the bound node. If a consumer of a bound node needs to refer to the syntax to affect the meaning of the code, that is a design smell.
### Every bound node type is either abstract or sealed
In `BoundNodes.xml`, a `Node` should have a base that is `BoundNode` or a node type declared `AbstractNode`. Do not inherit a concrete node type from another concrete node type.
......@@ -300,6 +300,12 @@ internal BoundExpression BindToNaturalType(BoundExpression expression, Diagnosti
hasErrors: true).WithSuppression(defaultExpr.IsSuppressed);
}
break;
case BoundStackAllocArrayCreation { Type: null } boundStackAlloc:
// This is a context in which the stackalloc could be either a pointer
// or a span. For backward compatibility we treat it as a pointer.
var type = new PointerTypeSymbol(TypeWithAnnotations.Create(boundStackAlloc.ElementType));
result = GenerateConversionForAssignment(type, boundStackAlloc, diagnostics);
break;
default:
result = expression;
break;
......@@ -3516,26 +3522,56 @@ private TypeSymbol GetStackAllocType(SyntaxNode node, TypeWithAnnotations elemen
{
var inLegalPosition = ReportBadStackAllocPosition(node, diagnostics);
hasErrors = !inLegalPosition;
if (inLegalPosition && !node.IsLocalVariableDeclarationInitializationForPointerStackalloc())
if (inLegalPosition && !isStackallocTargetTyped(node))
{
CheckFeatureAvailability(node, MessageID.IDS_FeatureRefStructs, diagnostics);
var spanType = GetWellKnownType(WellKnownType.System_Span_T, diagnostics, node);
if (!spanType.IsErrorType())
{
return ConstructNamedType(
type: spanType,
typeSyntax: node.Kind() == SyntaxKind.StackAllocArrayCreationExpression
? ((StackAllocArrayCreationExpressionSyntax)node).Type
: node,
typeArgumentsSyntax: default,
typeArguments: ImmutableArray.Create(elementTypeWithAnnotations),
basesBeingResolved: null,
diagnostics: diagnostics);
}
return ConstructNamedType(
type: spanType,
typeSyntax: node.Kind() == SyntaxKind.StackAllocArrayCreationExpression
? ((StackAllocArrayCreationExpressionSyntax)node).Type
: node,
typeArgumentsSyntax: default,
typeArguments: ImmutableArray.Create(elementTypeWithAnnotations),
basesBeingResolved: null,
diagnostics: diagnostics);
}
// We treat the stackalloc as target-typed, so we give it a null type for now.
return null;
// Is this a context in which a stackalloc expression could be converted to the corresponding pointer
// type? The only context that permits it is the initialization of a local variable declaration (when
// the declaration appears as a statement or as the first part of a for loop).
static bool isStackallocTargetTyped(SyntaxNode node)
{
Debug.Assert(node != null);
SyntaxNode equalsValueClause = node.Parent;
if (!equalsValueClause.IsKind(SyntaxKind.EqualsValueClause))
{
return false;
}
SyntaxNode variableDeclarator = equalsValueClause.Parent;
if (!variableDeclarator.IsKind(SyntaxKind.VariableDeclarator))
{
return false;
}
SyntaxNode variableDeclaration = variableDeclarator.Parent;
if (!variableDeclaration.IsKind(SyntaxKind.VariableDeclaration))
{
return false;
}
return
variableDeclaration.Parent.IsKind(SyntaxKind.LocalDeclarationStatement) ||
variableDeclaration.Parent.IsKind(SyntaxKind.ForStatement);
}
}
private BoundExpression BindStackAllocWithInitializer(
......@@ -3548,6 +3584,8 @@ private TypeSymbol GetStackAllocType(SyntaxNode node, TypeWithAnnotations elemen
bool hasErrors,
ImmutableArray<BoundExpression> boundInitExprOpt = default)
{
Debug.Assert(node.IsKind(SyntaxKind.ImplicitStackAllocArrayCreationExpression) || node.IsKind(SyntaxKind.StackAllocArrayCreationExpression));
if (boundInitExprOpt.IsDefault)
{
boundInitExprOpt = BindArrayInitializerExpressions(initSyntax, diagnostics, dimension: 1, rank: 1);
......
......@@ -844,16 +844,6 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost
BoundExpression expression = BindToNaturalType(BindValue(initializer, diagnostics, valueKind), diagnostics);
if (expression is BoundStackAllocArrayCreation boundStackAlloc &&
initializer.IsLocalVariableDeclarationInitializationForPointerStackalloc() &&
(initializer.Kind() == SyntaxKind.StackAllocArrayCreationExpression || initializer.Kind() == SyntaxKind.ImplicitStackAllocArrayCreationExpression))
{
var type = new PointerTypeSymbol(TypeWithAnnotations.Create(boundStackAlloc.ElementType));
expression = GenerateConversionForAssignment(type, boundStackAlloc, diagnostics, isRefAssignment: refKind != RefKind.None);
}
expression = BindToNaturalType(expression, diagnostics);
// Certain expressions (null literals, method groups and anonymous functions) have no type of
// their own and therefore cannot be the initializer of an implicitly typed local.
if (!expression.HasAnyErrors && !expression.HasExpressionType())
......
......@@ -304,7 +304,7 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
if (sourceExpression.Syntax.IsLocalVariableDeclarationInitializationForPointerStackalloc())
if (sourceExpression.NeedsToBeConverted())
{
Debug.Assert((object)sourceExpression.Type == null);
Debug.Assert((object)sourceExpression.ElementType != null);
......
......@@ -55,6 +55,11 @@ internal bool NeedsToBeConverted()
case BoundKind.TupleLiteral:
case BoundKind.UnconvertedSwitchExpression:
return true;
case BoundKind.StackAllocArrayCreation:
// A BoundStackAllocArrayCreation is given a null type when it is in a
// syntactic context where it could be either a pointer or a span, and
// in that case it requires conversion to one or the other.
return this.Type is null;
#if DEBUG
case BoundKind.Local when !WasConverted:
case BoundKind.Parameter when !WasConverted:
......
......@@ -1763,13 +1763,23 @@
<Field Name="Initializers" Type="ImmutableArray&lt;BoundExpression&gt;"/>
</Node>
<Node Name="BoundStackAllocArrayCreation" Base="BoundExpression">
<AbstractNode Name="BoundStackAllocArrayCreationBase" Base="BoundExpression">
<Field Name="Type" Type="TypeSymbol?" Override="true" Null="allow"/>
<Field Name="ElementType" Type="TypeSymbol" Null="disallow"/>
<Field Name="Count" Type="BoundExpression" Null="disallow" />
<Field Name="InitializerOpt" Type="BoundArrayInitialization?"/>
</AbstractNode>
<Node Name="BoundStackAllocArrayCreation" Base="BoundStackAllocArrayCreationBase">
<!-- A BoundStackAllocArrayCreation is given a null type when it is in a
syntactic context where it could be either a pointer or a span, and
in that case it requires conversion to one or the other. In the
special case that it is the direct initializer of a local variable
whose type is inferred, we treat it as a pointer. -->
<Field Name="Type" Type="TypeSymbol?" Override="true" Null="allow"/>
</Node>
<Node Name="BoundConvertedStackAllocExpression" Base="BoundStackAllocArrayCreation">
<Node Name="BoundConvertedStackAllocExpression" Base="BoundStackAllocArrayCreationBase">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
</Node>
......
......@@ -124,13 +124,16 @@ internal partial class BoundFixedLocalCollectionInitializer
protected override ImmutableArray<BoundNode> Children => ImmutableArray.Create<BoundNode>(this.Expression);
}
internal partial class BoundStackAllocArrayCreation
internal partial class BoundStackAllocArrayCreationBase
{
internal static ImmutableArray<BoundExpression> GetChildInitializers(BoundArrayInitialization arrayInitializer)
{
return arrayInitializer?.Initializers ?? ImmutableArray<BoundExpression>.Empty;
}
}
internal partial class BoundStackAllocArrayCreation
{
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(GetChildInitializers(this.InitializerOpt).Insert(0, this.Count));
}
......
......@@ -2769,7 +2769,7 @@ public override BoundNode VisitSizeOfOperator(BoundSizeOfOperator node)
return null;
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
private BoundNode VisitStackAllocArrayCreationBase(BoundStackAllocArrayCreationBase node)
{
VisitRvalue(node.Count);
......@@ -2784,10 +2784,14 @@ public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreat
return null;
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
{
return VisitStackAllocArrayCreationBase(node);
}
public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node)
{
VisitStackAllocArrayCreation(node);
return null;
return VisitStackAllocArrayCreationBase(node);
}
public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousObjectCreationExpression node)
......
......@@ -7574,7 +7574,7 @@ private void SetUnknownResultNullability(BoundExpression expression)
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
{
var result = base.VisitStackAllocArrayCreation(node);
Debug.Assert(node.Type is null || node.Type.IsPointerType() || node.Type.IsRefLikeType);
Debug.Assert(node.Type is null || node.Type.IsErrorType() || node.Type.IsPointerType() || node.Type.IsRefLikeType);
SetNotNullResult(node);
return result;
}
......
......@@ -6210,9 +6210,9 @@ public BoundArrayInitialization Update(ImmutableArray<BoundExpression> initializ
}
}
internal partial class BoundStackAllocArrayCreation : BoundExpression
internal abstract partial class BoundStackAllocArrayCreationBase : BoundExpression
{
protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, BoundArrayInitialization? initializerOpt, TypeSymbol? type, bool hasErrors = false)
protected BoundStackAllocArrayCreationBase(BoundKind kind, SyntaxNode syntax, TypeSymbol elementType, BoundExpression count, BoundArrayInitialization? initializerOpt, TypeSymbol? type, bool hasErrors = false)
: base(kind, syntax, type, hasErrors)
{
......@@ -6224,24 +6224,29 @@ protected BoundStackAllocArrayCreation(BoundKind kind, SyntaxNode syntax, TypeSy
this.InitializerOpt = initializerOpt;
}
public new TypeSymbol? Type => base.Type!;
public TypeSymbol ElementType { get; }
public BoundExpression Count { get; }
public BoundArrayInitialization? InitializerOpt { get; }
}
internal sealed partial class BoundStackAllocArrayCreation : BoundStackAllocArrayCreationBase
{
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())
: base(BoundKind.StackAllocArrayCreation, syntax, elementType, count, initializerOpt, type, hasErrors || count.HasErrors() || initializerOpt.HasErrors())
{
Debug.Assert(elementType is object, "Field 'elementType' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
Debug.Assert(count is object, "Field 'count' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
this.ElementType = elementType;
this.Count = count;
this.InitializerOpt = initializerOpt;
}
public TypeSymbol ElementType { get; }
public BoundExpression Count { get; }
public BoundArrayInitialization? InitializerOpt { get; }
public new TypeSymbol? Type => base.Type!;
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitStackAllocArrayCreation(this);
......@@ -6257,7 +6262,7 @@ public BoundStackAllocArrayCreation Update(TypeSymbol elementType, BoundExpressi
}
}
internal sealed partial class BoundConvertedStackAllocExpression : BoundStackAllocArrayCreation
internal sealed partial class BoundConvertedStackAllocExpression : BoundStackAllocArrayCreationBase
{
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())
......@@ -6274,7 +6279,7 @@ public BoundConvertedStackAllocExpression(SyntaxNode syntax, TypeSymbol elementT
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitConvertedStackAllocExpression(this);
public new BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, BoundArrayInitialization? initializerOpt, TypeSymbol type)
public BoundConvertedStackAllocExpression Update(TypeSymbol elementType, BoundExpression count, BoundArrayInitialization? initializerOpt, TypeSymbol type)
{
if (!TypeSymbol.Equals(elementType, this.ElementType, TypeCompareKind.ConsiderEverything) || count != this.Count || initializerOpt != this.InitializerOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
......
......@@ -12,10 +12,15 @@ internal sealed partial class LocalRewriter
{
public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression stackAllocNode)
{
return VisitStackAllocArrayCreation(stackAllocNode);
return VisitStackAllocArrayCreationBase(stackAllocNode);
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode)
{
return VisitStackAllocArrayCreationBase(stackAllocNode);
}
private BoundNode VisitStackAllocArrayCreationBase(BoundStackAllocArrayCreationBase stackAllocNode)
{
var rewrittenCount = VisitExpression(stackAllocNode.Count);
var type = stackAllocNode.Type;
......
......@@ -109,40 +109,6 @@ internal static bool IsValidScopeDesignator(this ExpressionSyntax expression)
}
}
/// <summary>
/// Is this a context in which a stackalloc expression could be converted to the corresponding pointer
/// type? The only context that permits it is the initialization of a local variable declaration (when
/// the declaration appears as a statement or as the first part of a for loop).
/// </summary>
internal static bool IsLocalVariableDeclarationInitializationForPointerStackalloc(this SyntaxNode node)
{
Debug.Assert(node != null);
SyntaxNode equalsValueClause = node.Parent;
if (!equalsValueClause.IsKind(SyntaxKind.EqualsValueClause))
{
return false;
}
SyntaxNode variableDeclarator = equalsValueClause.Parent;
if (!variableDeclarator.IsKind(SyntaxKind.VariableDeclarator))
{
return false;
}
SyntaxNode variableDeclaration = variableDeclarator.Parent;
if (!variableDeclaration.IsKind(SyntaxKind.VariableDeclaration))
{
return false;
}
return
variableDeclaration.Parent.IsKind(SyntaxKind.LocalDeclarationStatement) ||
variableDeclaration.Parent.IsKind(SyntaxKind.ForStatement);
}
/// <summary>
/// Because the instruction cannot have any values on the stack before CLR execution
/// we limited it to assignments and conditional expressions in C# 7.
......
......@@ -594,24 +594,24 @@ static void Method1()
}";
CreateCompilationWithMscorlibAndSpan(source, TestOptions.ReleaseDll, parseOptions: TestOptions.Regular7_3)
.VerifyDiagnostics(
// (6,15): error CS8652: The feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
// (6,15): error CS8370: Feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
// lock (stackalloc int[3] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "stackalloc").WithArguments("stackalloc in nested expressions", "8.0").WithLocation(6, 15),
// (6,15): error CS0185: 'stackalloc int[3]' is not a reference type as required by the lock statement
// (6,15): error CS0185: 'int*' is not a reference type as required by the lock statement
// lock (stackalloc int[3] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc int[3] { 1, 2, 3 }").WithArguments("stackalloc int[3]").WithLocation(6, 15),
// (7,15): error CS8652: The feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc int[3] { 1, 2, 3 }").WithArguments("int*").WithLocation(6, 15),
// (7,15): error CS8370: Feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
// lock (stackalloc int[ ] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "stackalloc").WithArguments("stackalloc in nested expressions", "8.0").WithLocation(7, 15),
// (7,15): error CS0185: 'stackalloc int[]' is not a reference type as required by the lock statement
// (7,15): error CS0185: 'int*' is not a reference type as required by the lock statement
// lock (stackalloc int[ ] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc int[ ] { 1, 2, 3 }").WithArguments("stackalloc int[]").WithLocation(7, 15),
// (8,15): error CS8652: The feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc int[ ] { 1, 2, 3 }").WithArguments("int*").WithLocation(7, 15),
// (8,15): error CS8370: Feature 'stackalloc in nested expressions' is not available in C# 7.3. Please use language version 8.0 or greater.
// lock (stackalloc [ ] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "stackalloc").WithArguments("stackalloc in nested expressions", "8.0").WithLocation(8, 15),
// (8,15): error CS0185: 'stackalloc int[]' is not a reference type as required by the lock statement
// (8,15): error CS0185: 'int*' is not a reference type as required by the lock statement
// lock (stackalloc [ ] { 1, 2, 3 }) {}
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc [ ] { 1, 2, 3 }").WithArguments("stackalloc int[]").WithLocation(8, 15)
Diagnostic(ErrorCode.ERR_LockNeedsReference, "stackalloc [ ] { 1, 2, 3 }").WithArguments("int*").WithLocation(8, 15)
);
CreateCompilationWithMscorlibAndSpan(source, TestOptions.ReleaseDll, parseOptions: TestOptions.Regular8)
.VerifyDiagnostics(
......@@ -1056,7 +1056,7 @@ public void Method3()
Assert.Equal("obj5", obj5.Identifier.Text);
var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value);
Assert.Null(obj5Value.Type);
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)obj5Value.Type).PointedAtType.SpecialType);
Assert.Equal(SpecialType.System_Double, ((IPointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType);
Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind);
}
......@@ -1159,7 +1159,7 @@ public void Method3()
Assert.Equal("obj5", obj5.Identifier.Text);
var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value);
Assert.Null(obj5Value.Type);
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)obj5Value.Type).PointedAtType.SpecialType);
Assert.Equal(SpecialType.System_Double, ((IPointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType);
Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind);
}
......@@ -2542,7 +2542,7 @@ public void Method1()
var stackallocInfo = model.GetSemanticInfoSummary(@stackalloc);
Assert.Null(stackallocInfo.Symbol);
Assert.Null(stackallocInfo.Type);
Assert.Equal("System.Double*", stackallocInfo.Type.ToTestDisplayString());
Assert.Equal("System.Int16*", stackallocInfo.ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.NoConversion, stackallocInfo.ImplicitConversion);
......@@ -2570,7 +2570,7 @@ public void Method1()
stackallocInfo = model.GetSemanticInfoSummary(@stackalloc);
Assert.Null(stackallocInfo.Symbol);
Assert.Null(stackallocInfo.Type);
Assert.Equal("System.Double*", stackallocInfo.Type.ToTestDisplayString());
Assert.Equal("System.Span<System.Int16>", stackallocInfo.ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.NoConversion, stackallocInfo.ImplicitConversion);
......
......@@ -85,7 +85,7 @@ public void Method()
Assert.Equal("obj5", obj5.Identifier.Text);
var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value);
Assert.Null(obj5Value.Type);
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)obj5Value.Type).PointedAtType.SpecialType);
Assert.Equal(SpecialType.System_Double, ((IPointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType);
Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind);
}
......@@ -160,7 +160,7 @@ public void Method()
Assert.Equal("obj5", obj5.Identifier.Text);
var obj5Value = model.GetSemanticInfoSummary(obj5.Initializer.Value);
Assert.Null(obj5Value.Type);
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)obj5Value.Type).PointedAtType.SpecialType);
Assert.Equal(SpecialType.System_Double, ((IPointerTypeSymbol)obj5Value.ConvertedType).PointedAtType.SpecialType);
Assert.Equal(ConversionKind.NoConversion, obj5Value.ImplicitConversion.Kind);
}
......
......@@ -4816,10 +4816,7 @@ unsafe public class Test
CreateCompilation(test, options: TestOptions.UnsafeDebugDll).VerifyDiagnostics(
// (4,14): error CS0518: Predefined type 'System.Span`1' is not defined or imported
// int* p = stackalloc int[1];
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(4, 14),
// (4,14): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'int*' is not possible.
// int* p = stackalloc int[1];
Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[1]").WithArguments("int", "int*").WithLocation(4, 14)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(4, 14)
);
}
......@@ -4839,10 +4836,7 @@ void M()
CreateCompilation(test, options: TestOptions.UnsafeDebugDll).VerifyDiagnostics(
// (6,33): error CS0518: Predefined type 'System.Span`1' is not defined or imported
// int*[] p = new int*[] { stackalloc int[1] };
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(6, 33),
// (6,33): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'int*' is not possible.
// int*[] p = new int*[] { stackalloc int[1] };
Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[1]").WithArguments("int", "int*").WithLocation(6, 33)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(6, 33)
);
}
......@@ -4905,10 +4899,7 @@ unsafe public static void Main()
CreateCompilation(test, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics(
// (6,39): error CS0518: Predefined type 'System.Span`1' is not defined or imported
// using (System.IDisposable v = stackalloc int[1])
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(6, 39),
// (6,39): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'IDisposable' is not possible.
// using (System.IDisposable v = stackalloc int[1])
Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int[1]").WithArguments("int", "System.IDisposable").WithLocation(6, 39)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1]").WithArguments("System.Span`1").WithLocation(6, 39)
);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册