Пример #1
0
        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);
        }
Пример #2
0
        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));
        }
Пример #3
0
 public override Conversion GetStackAllocConversion(
     BoundStackAllocArrayCreation sourceExpression,
     TypeSymbol destination,
     ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo
     )
 {
     // Conversions involving stackalloc expressions require a Binder.
     throw ExceptionUtilities.Unreachable;
 }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
 public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode)
 {
     return(VisitStackAllocArrayCreationBase(stackAllocNode));
 }
Пример #8
0
        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);
            }
        }
Пример #9
0
 public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     // Conversions involving stackalloc expressions require a Binder.
     throw ExceptionUtilities.Unreachable;
 }