@@ -5501,89 +5501,178 @@ static void zend_compile_foreach(zend_ast *ast) /* {{{ */
5501
5501
zend_ast * value_ast = ast -> child [1 ];
5502
5502
zend_ast * key_ast = ast -> child [2 ];
5503
5503
zend_ast * stmt_ast = ast -> child [3 ];
5504
- bool by_ref = value_ast -> kind == ZEND_AST_REF ;
5505
- bool is_variable = zend_is_variable (expr_ast ) && zend_can_write_to_variable (expr_ast );
5506
5504
5507
- znode expr_node , reset_node , value_node , key_node ;
5508
- zend_op * opline ;
5509
- uint32_t opnum_reset , opnum_fetch ;
5505
+ if (! value_ast && ! key_ast ) {
5506
+ bool by_ref = value_ast && value_ast -> kind == ZEND_AST_REF ;
5507
+ bool is_variable = zend_is_variable ( expr_ast ) && zend_can_write_to_variable ( expr_ast ) ;
5510
5508
5511
- if (key_ast ) {
5512
- if (key_ast -> kind == ZEND_AST_REF ) {
5513
- zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5509
+ znode expr_node , reset_node , value_node , key_node ;
5510
+ zend_op * opline ;
5511
+ uint32_t opnum_reset , opnum_fetch ;
5512
+
5513
+ if (key_ast ) {
5514
+ if (key_ast -> kind == ZEND_AST_REF ) {
5515
+ zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5516
+ }
5517
+ if (key_ast -> kind == ZEND_AST_ARRAY ) {
5518
+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5519
+ }
5514
5520
}
5515
- if (key_ast -> kind == ZEND_AST_ARRAY ) {
5516
- zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5521
+
5522
+ if (by_ref ) {
5523
+ value_ast = value_ast -> child [0 ];
5517
5524
}
5518
- }
5519
5525
5520
- if (by_ref ) {
5521
- value_ast = value_ast -> child [ 0 ] ;
5522
- }
5526
+ if (value_ast && value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs ( value_ast ) ) {
5527
+ by_ref = 1 ;
5528
+ }
5523
5529
5524
- if (value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs (value_ast )) {
5525
- by_ref = 1 ;
5526
- }
5530
+ if (by_ref && is_variable ) {
5531
+ zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
5532
+ } else {
5533
+ zend_compile_expr (& expr_node , expr_ast );
5534
+ }
5527
5535
5528
- if (by_ref && is_variable ) {
5529
- zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
5530
- } else {
5531
- zend_compile_expr (& expr_node , expr_ast );
5532
- }
5536
+ if (by_ref ) {
5537
+ zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5538
+ }
5533
5539
5534
- if (by_ref ) {
5535
- zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5536
- }
5540
+ opnum_reset = get_next_op_number ();
5541
+ opline = zend_emit_op (& reset_node , by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R , & expr_node , NULL );
5537
5542
5538
- opnum_reset = get_next_op_number ();
5539
- opline = zend_emit_op (& reset_node , by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R , & expr_node , NULL );
5543
+ zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
5540
5544
5541
- zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
5545
+ opnum_fetch = get_next_op_number ();
5546
+ opline = zend_emit_op (NULL , by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R , & reset_node , NULL );
5542
5547
5543
- opnum_fetch = get_next_op_number ();
5544
- opline = zend_emit_op (NULL , by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R , & reset_node , NULL );
5548
+ if (value_ast && is_this_fetch (value_ast )) {
5549
+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5550
+ } else if (value_ast && value_ast -> kind == ZEND_AST_VAR && zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5551
+ SET_NODE (opline -> op2 , & value_node );
5552
+ } else {
5553
+ opline -> op2_type = IS_VAR ;
5554
+ opline -> op2 .var = get_temporary_variable ();
5555
+ GET_NODE (& value_node , opline -> op2 );
5556
+ if (value_ast -> kind == ZEND_AST_ARRAY ) {
5557
+ zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5558
+ } else if (by_ref ) {
5559
+ zend_emit_assign_ref_znode (value_ast , & value_node );
5560
+ } else {
5561
+ zend_emit_assign_znode (value_ast , & value_node );
5562
+ }
5563
+ }
5545
5564
5546
- if (is_this_fetch (value_ast )) {
5547
- zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5548
- } else if (value_ast -> kind == ZEND_AST_VAR &&
5549
- zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5550
- SET_NODE (opline -> op2 , & value_node );
5565
+ if (key_ast ) {
5566
+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5567
+ zend_make_tmp_result (& key_node , opline );
5568
+ zend_emit_assign_znode (key_ast , & key_node );
5569
+ }
5570
+
5571
+ zend_compile_stmt (stmt_ast );
5572
+
5573
+ /* Place JMP and FE_FREE on the line where foreach starts. It would be
5574
+ * better to use the end line, but this information is not available
5575
+ * currently. */
5576
+ CG (zend_lineno ) = ast -> lineno ;
5577
+ zend_emit_jump (opnum_fetch );
5578
+
5579
+ opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5580
+ opline -> op2 .opline_num = get_next_op_number ();
5581
+
5582
+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5583
+ opline -> extended_value = get_next_op_number ();
5584
+
5585
+ zend_end_loop (opnum_fetch , & reset_node );
5586
+
5587
+ opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
5551
5588
} else {
5552
- opline -> op2_type = IS_VAR ;
5553
- opline -> op2 .var = get_temporary_variable ();
5554
- GET_NODE (& value_node , opline -> op2 );
5555
- if (value_ast -> kind == ZEND_AST_ARRAY ) {
5556
- zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5557
- } else if (by_ref ) {
5558
- zend_emit_assign_ref_znode (value_ast , & value_node );
5589
+ bool by_ref = value_ast && value_ast -> kind == ZEND_AST_REF ;
5590
+ bool is_variable = zend_is_variable (expr_ast ) && zend_can_write_to_variable (expr_ast );
5591
+
5592
+ znode expr_node , reset_node , value_node , key_node ;
5593
+ zend_op * opline ;
5594
+ uint32_t opnum_reset , opnum_fetch ;
5595
+
5596
+ if (key_ast ) {
5597
+ if (key_ast -> kind == ZEND_AST_REF ) {
5598
+ zend_error_noreturn (E_COMPILE_ERROR , "Key element cannot be a reference" );
5599
+ }
5600
+ if (key_ast -> kind == ZEND_AST_ARRAY ) {
5601
+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot use list as key element" );
5602
+ }
5603
+ }
5604
+
5605
+ if (by_ref ) {
5606
+ value_ast = value_ast -> child [0 ];
5607
+ }
5608
+
5609
+ if (value_ast && value_ast -> kind == ZEND_AST_ARRAY && zend_propagate_list_refs (value_ast )) {
5610
+ by_ref = 1 ;
5611
+ }
5612
+
5613
+ if (by_ref && is_variable ) {
5614
+ zend_compile_var (& expr_node , expr_ast , BP_VAR_W , 1 );
5559
5615
} else {
5560
- zend_emit_assign_znode ( value_ast , & value_node );
5616
+ zend_compile_expr ( & expr_node , expr_ast );
5561
5617
}
5562
- }
5563
5618
5564
- if (key_ast ) {
5565
- opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5566
- zend_make_tmp_result (& key_node , opline );
5567
- zend_emit_assign_znode (key_ast , & key_node );
5568
- }
5619
+ if (by_ref ) {
5620
+ zend_separate_if_call_and_write (& expr_node , expr_ast , BP_VAR_W );
5621
+ }
5569
5622
5570
- zend_compile_stmt (stmt_ast );
5623
+ opnum_reset = get_next_op_number ();
5624
+ opline = zend_emit_op (& reset_node , ZEND_FE_RESET_R , & expr_node , NULL );
5571
5625
5572
- /* Place JMP and FE_FREE on the line where foreach starts. It would be
5573
- * better to use the end line, but this information is not available
5574
- * currently. */
5575
- CG (zend_lineno ) = ast -> lineno ;
5576
- zend_emit_jump (opnum_fetch );
5626
+ zend_begin_loop (ZEND_FE_FREE , & reset_node , 0 );
5577
5627
5578
- opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5579
- opline -> op2 .opline_num = get_next_op_number ();
5628
+ opnum_fetch = get_next_op_number ();
5629
+ opline = zend_emit_op (NULL , ZEND_FE_FETCH_R , & reset_node , NULL );
5630
+ if (value_ast ) {
5631
+ if (is_this_fetch (value_ast )) {
5632
+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot re-assign $this" );
5633
+ } else
5634
+ if (value_ast -> kind == ZEND_AST_VAR && zend_try_compile_cv (& value_node , value_ast ) == SUCCESS ) {
5635
+ SET_NODE (opline -> op2 , & value_node );
5636
+ }
5637
+ else {
5638
+ opline -> op2_type = IS_VAR ;
5639
+ opline -> op2 .var = get_temporary_variable ();
5640
+ GET_NODE (& value_node , opline -> op2 );
5641
+ if (value_ast -> kind == ZEND_AST_ARRAY ) {
5642
+ zend_compile_list_assign (NULL , value_ast , & value_node , value_ast -> attr );
5643
+ } else
5644
+ if (by_ref ) {
5645
+ zend_emit_assign_ref_znode (value_ast , & value_node );
5646
+ } else {
5647
+ zend_emit_assign_znode (value_ast , & value_node );
5648
+ }
5649
+ }
5650
+ }
5580
5651
5581
- opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5582
- opline -> extended_value = get_next_op_number ();
5652
+ if (key_ast ) {
5653
+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5654
+ zend_make_tmp_result (& key_node , opline );
5655
+ zend_emit_assign_znode (key_ast , & key_node );
5656
+ }
5583
5657
5584
- zend_end_loop (opnum_fetch , & reset_node );
5658
+ zend_compile_stmt (stmt_ast );
5659
+
5660
+ /* Place JMP and FE_FREE on the line where foreach starts. It would be
5661
+ * better to use the end line, but this information is not available
5662
+ * currently. */
5663
+ CG (zend_lineno ) = ast -> lineno ;
5664
+ zend_emit_jump (opnum_fetch );
5665
+
5666
+ opline = & CG (active_op_array )-> opcodes [opnum_reset ];
5667
+ opline -> op2 .opline_num = get_next_op_number ();
5585
5668
5586
- opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
5669
+ opline = & CG (active_op_array )-> opcodes [opnum_fetch ];
5670
+ opline -> extended_value = get_next_op_number ();
5671
+
5672
+ zend_end_loop (opnum_fetch , & reset_node );
5673
+
5674
+ opline = zend_emit_op (NULL , ZEND_FE_FREE , & reset_node , NULL );
5675
+ }
5587
5676
}
5588
5677
/* }}} */
5589
5678
0 commit comments