private static void RewriteLocalDeclaration( CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, ArrayBuilder<BoundStatement> statements, BoundLocalDeclaration node) { Debug.Assert(node.ArgumentsOpt.IsDefault); var local = node.LocalSymbol; var syntax = node.Syntax; declaredLocals.Add(local); var voidType = compilation.GetSpecialType(SpecialType.System_Void); var objectType = compilation.GetSpecialType(SpecialType.System_Object); var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); var stringType = compilation.GetSpecialType(SpecialType.System_String); // <>CreateVariable(Type type, string name) var method = container.GetOrAddSynthesizedMethod( ExpressionCompilerConstants.CreateVariableMethodName, (c, n, s) => new PlaceholderMethodSymbol( c, s, n, voidType, m => ImmutableArray.Create<ParameterSymbol>( new SynthesizedParameterSymbol(m, typeType, ordinal: 0, refKind: RefKind.None), new SynthesizedParameterSymbol(m, stringType, ordinal: 1, refKind: RefKind.None)))); var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); var call = BoundCall.Synthesized( syntax, receiverOpt: null, method: method, arguments: ImmutableArray.Create<BoundExpression>(type, name)); statements.Add(new BoundExpressionStatement(syntax, call)); var initializer = node.InitializerOpt; if (initializer != null) { // Generate assignment to local. The assignment will // be rewritten in PlaceholderLocalRewriter. var assignment = new BoundAssignmentOperator( syntax, new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), initializer, RefKind.None, local.Type); statements.Add(new BoundExpressionStatement(syntax, assignment)); } }
public override object VisitLocalDeclaration(BoundLocalDeclaration node, object arg) { int slot = MakeSlot(node.LocalSymbol); // not initially assigned Assign(node, node.Initializer, !this.state.Reachable); if (node.Initializer != null) { VisitExpression(node.Initializer); // analyze the expression Assign(node, node.Initializer); } return(null); }
private static void RewriteLocalDeclaration( CSharpCompilation compilation, EENamedTypeSymbol container, HashSet <LocalSymbol> declaredLocals, ArrayBuilder <BoundStatement> statements, BoundLocalDeclaration node) { Debug.Assert(node.ArgumentsOpt.IsDefault); var local = node.LocalSymbol; var syntax = node.Syntax; declaredLocals.Add(local); var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); var stringType = compilation.GetSpecialType(SpecialType.System_String); var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor); // CreateVariable(Type type, string name) var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName); var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); bool hasCustomTypeInfoPayload; var customTypeInfoPayload = GetCustomTypeInfoPayload(local, syntax, compilation, out hasCustomTypeInfoPayload); var customTypeInfoPayloadId = GetCustomTypeInfoPayloadId(syntax, guidConstructor, hasCustomTypeInfoPayload); var call = BoundCall.Synthesized( syntax, receiverOpt: null, method: method, arguments: ImmutableArray.Create(type, name, customTypeInfoPayloadId, customTypeInfoPayload)); statements.Add(new BoundExpressionStatement(syntax, call)); var initializer = node.InitializerOpt; if (initializer != null) { // Generate assignment to local. The assignment will // be rewritten in PlaceholderLocalRewriter. var assignment = new BoundAssignmentOperator( syntax, new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), initializer, RefKind.None, local.Type); statements.Add(new BoundExpressionStatement(syntax, assignment)); } }
private static void RewriteLocalDeclaration( CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, ArrayBuilder<BoundStatement> statements, BoundLocalDeclaration node) { Debug.Assert(node.ArgumentsOpt.IsDefault); var local = node.LocalSymbol; var syntax = node.Syntax; declaredLocals.Add(local); var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); var stringType = compilation.GetSpecialType(SpecialType.System_String); var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor); // CreateVariable(Type type, string name) var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName); var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); bool hasCustomTypeInfoPayload; var customTypeInfoPayload = GetCustomTypeInfoPayload(local, syntax, compilation, out hasCustomTypeInfoPayload); var customTypeInfoPayloadId = GetCustomTypeInfoPayloadId(syntax, guidConstructor, hasCustomTypeInfoPayload); var call = BoundCall.Synthesized( syntax, receiverOpt: null, method: method, arguments: ImmutableArray.Create(type, name, customTypeInfoPayloadId, customTypeInfoPayload)); statements.Add(new BoundExpressionStatement(syntax, call)); var initializer = node.InitializerOpt; if (initializer != null) { // Generate assignment to local. The assignment will // be rewritten in PlaceholderLocalRewriter. var assignment = new BoundAssignmentOperator( syntax, new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), initializer, RefKind.None, local.Type); statements.Add(new BoundExpressionStatement(syntax, assignment)); } }
private BoundStatement MakeDeclarationUsingStatement(SyntaxNode syntax, BoundBlock body, ImmutableArray <LocalSymbol> locals, BoundLocalDeclaration declaration, Conversion iDisposableConversion, MethodSymbol disposeMethodOpt, AwaitableInfo awaitOpt, SyntaxToken awaitKeyword) { Debug.Assert(declaration != null); BoundBlock result = body; result = RewriteDeclarationUsingStatement(syntax, declaration, result, iDisposableConversion, awaitKeyword, awaitOpt, disposeMethodOpt); // Declare all locals in a single, top-level block so that the scope is correct in the debugger // (Dev10 has them all come into scope at once, not per-declaration.) return(new BoundBlock( syntax, locals, ImmutableArray.Create <BoundStatement>(result))); }
private static void RewriteLocalDeclaration( ArrayBuilder<BoundStatement> statements, BoundLocalDeclaration node) { Debug.Assert(node.ArgumentsOpt.IsDefault); var initializer = node.InitializerOpt; if (initializer != null) { var local = node.LocalSymbol; var syntax = node.Syntax; // Generate assignment to local. The assignment will // be rewritten in PlaceholderLocalRewriter. var assignment = new BoundAssignmentOperator( syntax, new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), initializer, RefKind.None, local.Type); statements.Add(new BoundExpressionStatement(syntax, assignment)); } }
private static void RewriteLocalDeclaration( ArrayBuilder <BoundStatement> statements, BoundLocalDeclaration node) { Debug.Assert(node.ArgumentsOpt.IsDefault); var initializer = node.InitializerOpt; if (initializer != null) { var local = node.LocalSymbol; var syntax = node.Syntax; // Generate assignment to local. The assignment will // be rewritten in PlaceholderLocalRewriter. var assignment = new BoundAssignmentOperator( syntax, new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), initializer, RefKind.None, local.Type); statements.Add(new BoundExpressionStatement(syntax, assignment)); } }
public override BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten) { return(Previous.InstrumentLocalInitialization(original, rewritten)); }
/// <summary> /// <![CDATA[ /// fixed(int* ptr = &v){ ... } == becomes ===> /// /// pinned ref int pinnedTemp = ref v; // pinning managed ref /// int* ptr = (int*)&pinnedTemp; // unsafe cast to unmanaged ptr /// . . . /// ]]> /// </summary> private BoundStatement InitializeFixedStatementGetPinnable( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type.TypeSymbol; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); var initializerType = initializerExpr.Type; var initializerSyntax = initializerExpr.Syntax; var getPinnableMethod = fixedInitializer.GetPinnableOpt; // intervening parens may have been skipped by the binder; find the declarator VariableDeclarationSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclarationSyntax>(); Debug.Assert(declarator != null); // pinned ref int pinnedTemp pinnedTemp = factory.SynthesizedLocal( getPinnableMethod.ReturnType.TypeSymbol, syntax: declarator, isPinned: true, //NOTE: different from the array and string cases // RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways) refKind: RefKind.RefReadOnly, kind: SynthesizedLocalKind.FixedReference); BoundExpression callReceiver; int currentConditionalAccessID = 0; bool needNullCheck = !initializerType.IsValueType; if (needNullCheck) { currentConditionalAccessID = _currentConditionalAccessID++; callReceiver = new BoundConditionalReceiver( initializerSyntax, currentConditionalAccessID, initializerType); } else { callReceiver = initializerExpr; } // .GetPinnable() var getPinnableCall = getPinnableMethod.IsStatic ? factory.Call(null, getPinnableMethod, callReceiver) : factory.Call(callReceiver, getPinnableMethod); // temp =ref .GetPinnable() var tempAssignment = factory.AssignmentExpression( factory.Local(pinnedTemp), getPinnableCall, isRef: true); // &pinnedTemp var addr = new BoundAddressOfOperator( factory.Syntax, factory.Local(pinnedTemp), type: fixedInitializer.ElementPointerType); // (int*)&pinnedTemp var pointerValue = factory.Convert( localType, addr, fixedInitializer.ElementPointerTypeConversion); // {pinnedTemp =ref .GetPinnable(), (int*)&pinnedTemp} BoundExpression pinAndGetPtr = factory.Sequence( locals: ImmutableArray <LocalSymbol> .Empty, sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment), result: pointerValue); if (needNullCheck) { // initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default; pinAndGetPtr = new BoundLoweredConditionalAccess( initializerSyntax, initializerExpr, hasValueMethodOpt: null, whenNotNull: pinAndGetPtr, whenNullOpt: null, // just return default(T*) currentConditionalAccessID, localType); } // ptr = initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default; BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), pinAndGetPtr)); return(localInit); }
internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNode syntax, SyntaxToken usingKeyword, SyntaxToken awaitKeyword, Binder originalBinder, UsingStatementBinder usingBinderOpt, DiagnosticBag diagnostics) { bool isUsingDeclaration = syntax.Kind() == SyntaxKind.LocalDeclarationStatement; bool isExpression = !isUsingDeclaration && syntax.Kind() != SyntaxKind.VariableDeclaration; bool hasAwait = awaitKeyword != default; Debug.Assert(isUsingDeclaration || usingBinderOpt != null); TypeSymbol disposableInterface = getDisposableInterface(hasAwait); Debug.Assert((object)disposableInterface != null); bool hasErrors = ReportUseSiteDiagnostics(disposableInterface, diagnostics, hasAwait ? awaitKeyword : usingKeyword); Conversion iDisposableConversion = Conversion.NoConversion; BoundLocalDeclaration declarationOpt = default; BoundExpression expressionOpt = null; AwaitableInfo awaitOpt = null; TypeSymbol declarationTypeOpt = null; MethodSymbol disposeMethodOpt = null; TypeSymbol awaitableTypeOpt = null; if (isExpression) { expressionOpt = usingBinderOpt.BindTargetExpression(diagnostics, originalBinder); hasErrors |= !populateDisposableConversionOrDisposeMethod(fromExpression: true); } else { VariableDeclarationSyntax declarationSyntax = isUsingDeclaration ? ((LocalDeclarationStatementSyntax)syntax).Declaration : (VariableDeclarationSyntax)syntax; declarationOpt = originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics); Debug.Assert(declarationOpt != null); declarationTypeOpt = declarationOpt.DeclaredType.Type; hasErrors |= !populateDisposableConversionOrDisposeMethod(fromExpression: false); } if (hasAwait) { BoundAwaitableValuePlaceholder placeholderOpt; if (awaitableTypeOpt is null) { placeholderOpt = null; } else { hasErrors |= ReportUseSiteDiagnostics(awaitableTypeOpt, diagnostics, awaitKeyword); placeholderOpt = new BoundAwaitableValuePlaceholder(syntax, awaitableTypeOpt).MakeCompilerGenerated(); } // even if we don't have a proper value to await, we'll still report bad usages of `await` awaitOpt = originalBinder.BindAwaitInfo(placeholderOpt, syntax, awaitKeyword.GetLocation(), diagnostics, ref hasErrors); } // This is not awesome, but its factored. // In the future it might be better to have a seperate shared type that we add the info to, and have the callers create the appropriate bound nodes from it if (isUsingDeclaration) { return(new BoundUsingLocalDeclaration(syntax, disposeMethodOpt, iDisposableConversion, awaitOpt, declarationOpt, hasErrors)); } else { BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(usingBinderOpt._syntax.Statement, diagnostics); return(new BoundUsingStatement( usingBinderOpt._syntax, usingBinderOpt.Locals, declarationOpt, expressionOpt, iDisposableConversion, boundBody, awaitOpt, disposeMethodOpt, hasErrors)); } // initializes iDisposableConversion, awaitableTypeOpt and disposeMethodOpt bool populateDisposableConversionOrDisposeMethod(bool fromExpression) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = classifyConversion(fromExpression, disposableInterface, ref useSiteDiagnostics); diagnostics.Add(syntax, useSiteDiagnostics); if (iDisposableConversion.IsImplicit) { if (hasAwait) { awaitableTypeOpt = originalBinder.Compilation.GetWellKnownType(WellKnownType.core_Threading_Tasks_ValueTask); } return(true); } TypeSymbol type = fromExpression ? expressionOpt.Type : declarationTypeOpt; // If this is a ref struct, or we're in a valid asynchronous using, try binding via pattern. // We won't need to try and bind a second time if it fails, as async dispose can't be pattern based (ref structs are not allowed in async methods) if (!(type is null) && (type.IsRefLikeType || hasAwait)) { BoundExpression receiver = fromExpression ? expressionOpt : new BoundLocal(syntax, declarationOpt.LocalSymbol, null, type) { WasCompilerGenerated = true }; disposeMethodOpt = originalBinder.TryFindDisposePatternMethod(receiver, syntax, hasAwait, diagnostics); if (!(disposeMethodOpt is null)) { if (hasAwait) { awaitableTypeOpt = disposeMethodOpt.ReturnType.TypeSymbol; } return(true); } } if (type is null || !type.IsErrorType()) { // Retry with a different assumption about whether the `using` is async TypeSymbol alternateInterface = getDisposableInterface(!hasAwait); HashSet <DiagnosticInfo> ignored = null; Conversion alternateConversion = classifyConversion(fromExpression, alternateInterface, ref ignored); bool wrongAsync = alternateConversion.IsImplicit; ErrorCode errorCode = wrongAsync ? (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDispWrongAsync : ErrorCode.ERR_NoConvToIDispWrongAsync) : (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDisp : ErrorCode.ERR_NoConvToIDisp); Error(diagnostics, errorCode, syntax, declarationTypeOpt ?? expressionOpt.Display); } return(false); } Conversion classifyConversion(bool fromExpression, TypeSymbol targetInterface, ref HashSet <DiagnosticInfo> diag) { return(fromExpression ? originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, targetInterface, ref diag) : originalBinder.Conversions.ClassifyImplicitConversionFromType(declarationTypeOpt, targetInterface, ref diag)); } TypeSymbol getDisposableInterface(bool isAsync) { return(isAsync ? originalBinder.Compilation.GetWellKnownType(WellKnownType.core_IAsyncDisposable) : originalBinder.Compilation.GetSpecialType(SpecialType.System_IDisposable)); } }
public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node) { CheckDeclared(node.LocalSymbol); base.VisitLocalDeclaration(node); return(null); }
public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node) { return(RewriteLocalDeclaration(node, node.Syntax, node.LocalSymbol, VisitExpression(node.InitializerOpt), node.HasErrors)); }
public override BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentLocalInitialization(original, rewritten))); }
/// <summary> /// <![CDATA[ /// fixed(int* ptr = arr){ ... } == becomes ===> /// /// pinned int[] pinnedTemp = arr; // pinning managed ref /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0 /// (int*)&pinnedTemp[0]: // unsafe cast to unmanaged ptr /// 0; /// . . . /// ]]> /// </summary> private BoundStatement InitializeFixedStatementArrayLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type.TypeSymbol; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)pinnedTemp.Type.TypeSymbol; TypeSymbolWithAnnotations arrayElementType = arrayType.ElementType; // NOTE: we pin the array, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); //(pinnedTemp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr); //(pinnedTemp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayType.IsSZArray) { lengthCall = factory.ArrayLength(factory.Local(pinnedTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.Int32NotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit)); }
/// <summary> /// fixed(char* ptr = stringVar){ ... } == becomes ===> /// /// pinned string pinnedTemp = stringVar; // pinning managed ref /// char* ptr = (char*)pinnedTemp; // unsafe cast to unmanaged ptr /// if (pinnedTemp != null) ptr += OffsetToStringData(); /// . . . /// </summary> private BoundStatement InitializeFixedStatementStringLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type.TypeSymbol; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; // intervening parens may have been skipped by the binder; find the declarator VariableDeclarationSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclarationSyntax>(); Debug.Assert(declarator != null); pinnedTemp = factory.SynthesizedLocal( initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedReference); // NOTE: we pin the string, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); BoundStatement stringTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr); // (char*)pinnedTemp; var addr = factory.Convert( fixedInitializer.ElementPointerType, factory.Local(pinnedTemp), Conversion.PinnedObjectToPointer); var convertedStringTemp = factory.Convert( localType, addr, fixedInitializer.ElementPointerTypeConversion); BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), convertedStringTemp)); BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(localSymbol), BinaryOperatorKind.NotEqual); BoundExpression helperCall; MethodSymbol offsetMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod)) { helperCall = factory.Call(receiver: null, method: offsetMethod); } else { helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray <BoundExpression> .Empty, ErrorTypeSymbol.UnknownResultType); } BoundExpression addition = factory.Binary(BinaryOperatorKind.PointerAndInt32Addition, localType, factory.Local(localSymbol), helperCall); BoundStatement conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition)); return(factory.Block(stringTempInit, localInit, conditionalAdd)); }
// records locals into given scope // converts initializers into assignments public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node) { return RewriteLocalDeclaration(node.Syntax, node.LocalSymbol, (BoundExpression)Visit(node.InitializerOpt), node.HasErrors); }
public override BoundNode VisitFixedStatement(BoundFixedStatement node) { BoundLocalDeclaration localDecl = node.Declaration; int numFixedLocals = 1; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(node.Locals.Length); localBuilder.AddRange(node.Locals); var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(numFixedLocals + 1 + 1); //+1 for body, +1 for hidden seq point var cleanup = new BoundStatement[numFixedLocals]; { LocalSymbol pinnedTemp; statementBuilder.Add(InitializeFixedStatementLocal(localDecl, _factory, out pinnedTemp)); localBuilder.Add(pinnedTemp); // NOTE: Dev10 nulls out the locals in declaration order (as opposed to "popping" them in reverse order). if (pinnedTemp.RefKind == RefKind.None) { // temp = null; cleanup[0] = _factory.Assignment(_factory.Local(pinnedTemp), _factory.Null(pinnedTemp.Type.TypeSymbol)); } else { Debug.Assert(!pinnedTemp.Type.IsManagedType); // temp = ref *default(T*); cleanup[0] = _factory.Assignment(_factory.Local(pinnedTemp), new BoundPointerIndirectionOperator( _factory.Syntax, _factory.Default(new PointerTypeSymbol(pinnedTemp.Type)), pinnedTemp.Type.TypeSymbol), isRef: true); } } BoundStatement rewrittenBody = VisitStatement(node.Body); statementBuilder.Add(rewrittenBody); statementBuilder.Add(_factory.HiddenSequencePoint()); Debug.Assert(statementBuilder.Count == numFixedLocals + 1 + 1); // In principle, the cleanup code (i.e. nulling out the pinned variables) is always // in a finally block. However, we can optimize finally away (keeping the cleanup // code) in cases where both of the following are true: // 1) there are no branches out of the fixed statement; and // 2) the fixed statement is not in a try block (syntactic or synthesized). if (IsInTryBlock(node) || HasGotoOut(rewrittenBody)) { return(_factory.Block( localBuilder.ToImmutableAndFree(), new BoundTryStatement( _factory.Syntax, _factory.Block(statementBuilder.ToImmutableAndFree()), ImmutableArray <BoundCatchBlock> .Empty, _factory.Block(cleanup)))); } else { statementBuilder.AddRange(cleanup); return(_factory.Block(localBuilder.ToImmutableAndFree(), statementBuilder.ToImmutableAndFree())); } }
public virtual BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten) { Debug.Assert(original.Syntax.Kind() == SyntaxKind.VariableDeclaration || original.Syntax.Kind() == SyntaxKind.LocalDeclarationStatement); return(InstrumentStatement(original, rewritten)); }