public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { if (sourceExpression.Syntax.IsVariableDeclarationInitialization()) { Debug.Assert((object)sourceExpression.Type == null); Debug.Assert(sourceExpression.ElementType != null); var sourceAsPointer = new PointerTypeSymbol(TypeSymbolWithAnnotations.Create(sourceExpression.ElementType)); var pointerConversion = ClassifyImplicitConversionFromType(sourceAsPointer, destination, ref useSiteDiagnostics); if (pointerConversion.IsValid) { return(Conversion.MakeStackAllocToPointerType(pointerConversion)); } else { var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics); if (spanType.TypeKind == TypeKind.Struct && spanType.IsByRefLikeType) { var spanType_T = spanType.Construct(sourceExpression.ElementType); var spanConversion = ClassifyImplicitConversionFromType(spanType_T, destination, ref useSiteDiagnostics); if (spanConversion.Exists) { return(Conversion.MakeStackAllocToSpanType(spanConversion)); } } } } return(Conversion.NoConversion); }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node) { BoundExpression rewrittenCount = VisitExpression(node.Count); // From ILGENREC::genExpr: // EDMAURER always perform a checked multiply regardless of the context. // localloc takes an unsigned native int. When a user specifies a negative // count of elements, per spec, the behavior is undefined. So convert element // count to unsigned. // NOTE: to match this special case logic, we're going to construct the multiplication // ourselves, rather than calling MakeSizeOfMultiplication (which inserts various checks // and conversions). TypeSymbol uintType = factory.SpecialType(SpecialType.System_UInt32); TypeSymbol uintPtrType = factory.SpecialType(SpecialType.System_UIntPtr); // Why convert twice? Because dev10 actually uses an explicit conv_u instruction and the normal conversion // from int32 to native uint is emitted as conv_i. The behavior we want to emulate is to re-interpret // (i.e. unchecked) an int32 as unsigned (i.e. uint32) and then convert it to a native uint *without* sign // extension. BoundExpression convertedCount = factory.Convert(uintType, rewrittenCount, Conversion.ExplicitNumeric); convertedCount = factory.Convert(uintPtrType, convertedCount, Conversion.IntegerToPointer); BoundExpression sizeOfExpression = factory.Sizeof(((PointerTypeSymbol)node.Type).PointedAtType); BinaryOperatorKind multiplicationKind = BinaryOperatorKind.Checked | BinaryOperatorKind.UIntMultiplication; //"UInt" just to make it unsigned BoundExpression product = factory.Binary(multiplicationKind, uintPtrType, convertedCount, sizeOfExpression); return(node.Update(product, node.Type)); }
public override Conversion GetStackAllocConversion( BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo ) { // Conversions involving stackalloc expressions require a Binder. throw ExceptionUtilities.Unreachable; }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } var elementType = stackAllocNode.ElementType; if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type)); } else if (type.OriginalDefinition == _compilation.GetWellKnownType(WellKnownType.System_Span_T)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var sideEffects = ArrayBuilder <BoundExpression> .GetInstance(); var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var countTemp = CaptureExpressionInTempIfNeeded(rewrittenCount, sideEffects, locals); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, spanType); BoundExpression constructorCall; if (TryGetWellKnownTypeMember(stackAllocNode.Syntax, WellKnownMember.System_Span_T__ctor, out MethodSymbol spanConstructor)) { constructorCall = _factory.New((MethodSymbol)spanConstructor.SymbolAsMember(spanType), stackAllocNode, countTemp); } else { constructorCall = new BoundBadExpression( syntax: stackAllocNode.Syntax, resultKind: LookupResultKind.NotInvocable, symbols: ImmutableArray <Symbol> .Empty, childBoundNodes: ImmutableArray <BoundExpression> .Empty, type: ErrorTypeSymbol.UnknownResultType); } return(new BoundSequence( syntax: stackAllocNode.Syntax, locals: locals.ToImmutableAndFree(), sideEffects: sideEffects.ToImmutableAndFree(), value: constructorCall, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { 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); pointerConversion = ClassifyImplicitConversionFromType(sourceAsPointer, destination, ref useSiteDiagnostics); if (pointerConversion.IsValid) { // Report unsafe errors _binder.ReportUnsafeIfNotAllowed(sourceExpression.Syntax.Location, ref useSiteDiagnostics); return(Conversion.MakeStackAllocToPointerType(pointerConversion)); } else { var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics); if (spanType.TypeKind == TypeKind.Struct && spanType.IsByRefLikeType) { var spanType_T = spanType.Construct(sourceExpression.ElementType); var spanConversion = ClassifyImplicitConversionFromType(spanType_T, destination, ref useSiteDiagnostics); if (spanConversion.Exists) { // Report errors if Span ctor is missing, or using an older C# version Binder.CheckFeatureAvailability(sourceExpression.Syntax, MessageID.IDS_FeatureRefStructs, ref useSiteDiagnostics); Binder.GetWellKnownTypeMember(_binder.Compilation, WellKnownMember.System_Span_T__ctor, out DiagnosticInfo memberDiagnosticInfo); HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, memberDiagnosticInfo); return(Conversion.MakeStackAllocToSpanType(spanConversion)); } } } } return(Conversion.NoConversion); }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } var elementType = stackAllocNode.ElementType; if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type)); } else if (type.IsSpanType()) { 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); var spanCtor = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor).SymbolAsMember(spanType); var ctorCall = _factory.New(spanCtor, stackAllocNode, countTemp); return(new BoundSequence( syntax: stackAllocNode.Syntax, locals: ImmutableArray.Create(countTemp.LocalSymbol), sideEffects: ImmutableArray.Create <BoundExpression>(countTempAssignment), value: ctorCall, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { return(VisitStackAllocArrayCreationBase(stackAllocNode)); }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } 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, initializerOpt, stackAllocNode.Type)); } else if (TypeSymbol.Equals(type.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.ConsiderEverything2)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var sideEffects = ArrayBuilder <BoundExpression> .GetInstance(); var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var countTemp = CaptureExpressionInTempIfNeeded(rewrittenCount, sideEffects, locals, SynthesizedLocalKind.Spill); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); stackAllocNode = new BoundConvertedStackAllocExpression( stackAllocNode.Syntax, elementType, stackSize, initializerOpt, _compilation.CreatePointerTypeSymbol(elementType)); BoundExpression constructorCall; if (TryGetWellKnownTypeMember(stackAllocNode.Syntax, WellKnownMember.System_Span_T__ctor, out MethodSymbol spanConstructor)) { constructorCall = _factory.New((MethodSymbol)spanConstructor.SymbolAsMember(spanType), stackAllocNode, countTemp); } else { constructorCall = new BoundBadExpression( syntax: stackAllocNode.Syntax, resultKind: LookupResultKind.NotInvocable, symbols: ImmutableArray <Symbol> .Empty, childBoundNodes: ImmutableArray <BoundExpression> .Empty, type: ErrorTypeSymbol.UnknownResultType); } // The stackalloc instruction requires that the evaluation stack contains only its parameter when executed. // We arrange to clear the stack by wrapping it in a SpillSequence, which will cause pending computations // to be spilled, and also by storing the result in a temporary local, so that the result does not get // hoisted/spilled into some state machine. If that temp local needs to be spilled that will result in an // error. _needsSpilling = true; var tempAccess = _factory.StoreToTemp(constructorCall, out BoundAssignmentOperator tempAssignment, syntaxOpt: stackAllocNode.Syntax); sideEffects.Add(tempAssignment); locals.Add(tempAccess.LocalSymbol); return(new BoundSpillSequence( syntax: stackAllocNode.Syntax, locals: locals.ToImmutableAndFree(), sideEffects: sideEffects.ToImmutableAndFree(), value: tempAccess, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { // Conversions involving stackalloc expressions require a Binder. throw ExceptionUtilities.Unreachable; }